1/* 2 * Rockchip IO Voltage Domain driver 3 * 4 * Copyright 2014 MundoReader S.L. 5 * Copyright 2014 Google, Inc. 6 * 7 * This software is licensed under the terms of the GNU General Public 8 * License version 2, as published by the Free Software Foundation, and 9 * may be copied, distributed, and modified under those terms. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/err.h> 20#include <linux/mfd/syscon.h> 21#include <linux/of.h> 22#include <linux/platform_device.h> 23#include <linux/regmap.h> 24#include <linux/regulator/consumer.h> 25 26#define MAX_SUPPLIES 16 27 28/* 29 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under 30 * "Recommended Operating Conditions" for "Digital GPIO". When the typical 31 * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V. 32 * 33 * They are used like this: 34 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the 35 * SoC we're at 3.3. 36 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider 37 * that to be an error. 38 */ 39#define MAX_VOLTAGE_1_8 1980000 40#define MAX_VOLTAGE_3_3 3600000 41 42#define RK3288_SOC_CON2 0x24c 43#define RK3288_SOC_CON2_FLASH0 BIT(7) 44#define RK3288_SOC_FLASH_SUPPLY_NUM 2 45 46#define RK3368_SOC_CON15 0x43c 47#define RK3368_SOC_CON15_FLASH0 BIT(14) 48#define RK3368_SOC_FLASH_SUPPLY_NUM 2 49 50struct rockchip_iodomain; 51 52/** 53 * @supplies: voltage settings matching the register bits. 54 */ 55struct rockchip_iodomain_soc_data { 56 int grf_offset; 57 const char *supply_names[MAX_SUPPLIES]; 58 void (*init)(struct rockchip_iodomain *iod); 59}; 60 61struct rockchip_iodomain_supply { 62 struct rockchip_iodomain *iod; 63 struct regulator *reg; 64 struct notifier_block nb; 65 int idx; 66}; 67 68struct rockchip_iodomain { 69 struct device *dev; 70 struct regmap *grf; 71 struct rockchip_iodomain_soc_data *soc_data; 72 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES]; 73}; 74 75static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply, 76 int uV) 77{ 78 struct rockchip_iodomain *iod = supply->iod; 79 u32 val; 80 int ret; 81 82 /* set value bit */ 83 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1; 84 val <<= supply->idx; 85 86 /* apply hiword-mask */ 87 val |= (BIT(supply->idx) << 16); 88 89 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val); 90 if (ret) 91 dev_err(iod->dev, "Couldn't write to GRF\n"); 92 93 return ret; 94} 95 96static int rockchip_iodomain_notify(struct notifier_block *nb, 97 unsigned long event, 98 void *data) 99{ 100 struct rockchip_iodomain_supply *supply = 101 container_of(nb, struct rockchip_iodomain_supply, nb); 102 int uV; 103 int ret; 104 105 /* 106 * According to Rockchip it's important to keep the SoC IO domain 107 * higher than (or equal to) the external voltage. That means we need 108 * to change it before external voltage changes happen in the case 109 * of an increase. 110 * 111 * Note that in the "pre" change we pick the max possible voltage that 112 * the regulator might end up at (the client requests a range and we 113 * don't know for certain the exact voltage). Right now we rely on the 114 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients 115 * request something like a max of 3.6V when they really want 3.3V. 116 * We could attempt to come up with better rules if this fails. 117 */ 118 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { 119 struct pre_voltage_change_data *pvc_data = data; 120 121 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV); 122 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE | 123 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) { 124 uV = (unsigned long)data; 125 } else { 126 return NOTIFY_OK; 127 } 128 129 dev_dbg(supply->iod->dev, "Setting to %d\n", uV); 130 131 if (uV > MAX_VOLTAGE_3_3) { 132 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV); 133 134 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 135 return NOTIFY_BAD; 136 } 137 138 ret = rockchip_iodomain_write(supply, uV); 139 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 140 return NOTIFY_BAD; 141 142 dev_info(supply->iod->dev, "Setting to %d done\n", uV); 143 return NOTIFY_OK; 144} 145 146static void rk3288_iodomain_init(struct rockchip_iodomain *iod) 147{ 148 int ret; 149 u32 val; 150 151 /* if no flash supply we should leave things alone */ 152 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg) 153 return; 154 155 /* 156 * set flash0 iodomain to also use this framework 157 * instead of a special gpio. 158 */ 159 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16); 160 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val); 161 if (ret < 0) 162 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 163} 164 165static void rk3368_iodomain_init(struct rockchip_iodomain *iod) 166{ 167 int ret; 168 u32 val; 169 170 /* if no flash supply we should leave things alone */ 171 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg) 172 return; 173 174 /* 175 * set flash0 iodomain to also use this framework 176 * instead of a special gpio. 177 */ 178 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16); 179 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val); 180 if (ret < 0) 181 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 182} 183 184/* 185 * On the rk3188 the io-domains are handled by a shared register with the 186 * lower 8 bits being still being continuing drive-strength settings. 187 */ 188static const struct rockchip_iodomain_soc_data soc_data_rk3188 = { 189 .grf_offset = 0x104, 190 .supply_names = { 191 NULL, 192 NULL, 193 NULL, 194 NULL, 195 NULL, 196 NULL, 197 NULL, 198 NULL, 199 "ap0", 200 "ap1", 201 "cif", 202 "flash", 203 "vccio0", 204 "vccio1", 205 "lcdc0", 206 "lcdc1", 207 }, 208}; 209 210static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { 211 .grf_offset = 0x380, 212 .supply_names = { 213 "lcdc", /* LCDC_VDD */ 214 "dvp", /* DVPIO_VDD */ 215 "flash0", /* FLASH0_VDD (emmc) */ 216 "flash1", /* FLASH1_VDD (sdio1) */ 217 "wifi", /* APIO3_VDD (sdio0) */ 218 "bb", /* APIO5_VDD */ 219 "audio", /* APIO4_VDD */ 220 "sdcard", /* SDMMC0_VDD (sdmmc) */ 221 "gpio30", /* APIO1_VDD */ 222 "gpio1830", /* APIO2_VDD */ 223 }, 224 .init = rk3288_iodomain_init, 225}; 226 227static const struct rockchip_iodomain_soc_data soc_data_rk3368 = { 228 .grf_offset = 0x900, 229 .supply_names = { 230 NULL, /* reserved */ 231 "dvp", /* DVPIO_VDD */ 232 "flash0", /* FLASH0_VDD (emmc) */ 233 "wifi", /* APIO2_VDD (sdio0) */ 234 NULL, 235 "audio", /* APIO3_VDD */ 236 "sdcard", /* SDMMC0_VDD (sdmmc) */ 237 "gpio30", /* APIO1_VDD */ 238 "gpio1830", /* APIO4_VDD (gpujtag) */ 239 }, 240 .init = rk3368_iodomain_init, 241}; 242 243static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = { 244 .grf_offset = 0x100, 245 .supply_names = { 246 NULL, 247 NULL, 248 NULL, 249 NULL, 250 "pmu", /*PMU IO domain*/ 251 "vop", /*LCDC IO domain*/ 252 }, 253}; 254 255static const struct of_device_id rockchip_iodomain_match[] = { 256 { 257 .compatible = "rockchip,rk3188-io-voltage-domain", 258 .data = (void *)&soc_data_rk3188 259 }, 260 { 261 .compatible = "rockchip,rk3288-io-voltage-domain", 262 .data = (void *)&soc_data_rk3288 263 }, 264 { 265 .compatible = "rockchip,rk3368-io-voltage-domain", 266 .data = (void *)&soc_data_rk3368 267 }, 268 { 269 .compatible = "rockchip,rk3368-pmu-io-voltage-domain", 270 .data = (void *)&soc_data_rk3368_pmu 271 }, 272 { /* sentinel */ }, 273}; 274MODULE_DEVICE_TABLE(of, rockchip_iodomain_match); 275 276static int rockchip_iodomain_probe(struct platform_device *pdev) 277{ 278 struct device_node *np = pdev->dev.of_node; 279 const struct of_device_id *match; 280 struct rockchip_iodomain *iod; 281 int i, ret = 0; 282 283 if (!np) 284 return -ENODEV; 285 286 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL); 287 if (!iod) 288 return -ENOMEM; 289 290 iod->dev = &pdev->dev; 291 platform_set_drvdata(pdev, iod); 292 293 match = of_match_node(rockchip_iodomain_match, np); 294 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data; 295 296 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 297 if (IS_ERR(iod->grf)) { 298 dev_err(&pdev->dev, "couldn't find grf regmap\n"); 299 return PTR_ERR(iod->grf); 300 } 301 302 for (i = 0; i < MAX_SUPPLIES; i++) { 303 const char *supply_name = iod->soc_data->supply_names[i]; 304 struct rockchip_iodomain_supply *supply = &iod->supplies[i]; 305 struct regulator *reg; 306 int uV; 307 308 if (!supply_name) 309 continue; 310 311 reg = devm_regulator_get_optional(iod->dev, supply_name); 312 if (IS_ERR(reg)) { 313 ret = PTR_ERR(reg); 314 315 /* If a supply wasn't specified, that's OK */ 316 if (ret == -ENODEV) 317 continue; 318 else if (ret != -EPROBE_DEFER) 319 dev_err(iod->dev, "couldn't get regulator %s\n", 320 supply_name); 321 goto unreg_notify; 322 } 323 324 /* set initial correct value */ 325 uV = regulator_get_voltage(reg); 326 327 /* must be a regulator we can get the voltage of */ 328 if (uV < 0) { 329 dev_err(iod->dev, "Can't determine voltage: %s\n", 330 supply_name); 331 goto unreg_notify; 332 } 333 334 if (uV > MAX_VOLTAGE_3_3) { 335 dev_crit(iod->dev, 336 "%d uV is too high. May damage SoC!\n", 337 uV); 338 ret = -EINVAL; 339 goto unreg_notify; 340 } 341 342 /* setup our supply */ 343 supply->idx = i; 344 supply->iod = iod; 345 supply->reg = reg; 346 supply->nb.notifier_call = rockchip_iodomain_notify; 347 348 ret = rockchip_iodomain_write(supply, uV); 349 if (ret) { 350 supply->reg = NULL; 351 goto unreg_notify; 352 } 353 354 /* register regulator notifier */ 355 ret = regulator_register_notifier(reg, &supply->nb); 356 if (ret) { 357 dev_err(&pdev->dev, 358 "regulator notifier request failed\n"); 359 supply->reg = NULL; 360 goto unreg_notify; 361 } 362 } 363 364 if (iod->soc_data->init) 365 iod->soc_data->init(iod); 366 367 return 0; 368 369unreg_notify: 370 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 371 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 372 373 if (io_supply->reg) 374 regulator_unregister_notifier(io_supply->reg, 375 &io_supply->nb); 376 } 377 378 return ret; 379} 380 381static int rockchip_iodomain_remove(struct platform_device *pdev) 382{ 383 struct rockchip_iodomain *iod = platform_get_drvdata(pdev); 384 int i; 385 386 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 387 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 388 389 if (io_supply->reg) 390 regulator_unregister_notifier(io_supply->reg, 391 &io_supply->nb); 392 } 393 394 return 0; 395} 396 397static struct platform_driver rockchip_iodomain_driver = { 398 .probe = rockchip_iodomain_probe, 399 .remove = rockchip_iodomain_remove, 400 .driver = { 401 .name = "rockchip-iodomain", 402 .of_match_table = rockchip_iodomain_match, 403 }, 404}; 405 406module_platform_driver(rockchip_iodomain_driver); 407 408MODULE_DESCRIPTION("Rockchip IO-domain driver"); 409MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 410MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>"); 411MODULE_LICENSE("GPL v2"); 412