Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13-rc3 532 lines 13 kB view raw
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 RK3328_SOC_CON4 0x410 47#define RK3328_SOC_CON4_VCCIO2 BIT(7) 48#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1 49 50#define RK3368_SOC_CON15 0x43c 51#define RK3368_SOC_CON15_FLASH0 BIT(14) 52#define RK3368_SOC_FLASH_SUPPLY_NUM 2 53 54#define RK3399_PMUGRF_CON0 0x180 55#define RK3399_PMUGRF_CON0_VSEL BIT(8) 56#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9 57 58struct rockchip_iodomain; 59 60/** 61 * @supplies: voltage settings matching the register bits. 62 */ 63struct rockchip_iodomain_soc_data { 64 int grf_offset; 65 const char *supply_names[MAX_SUPPLIES]; 66 void (*init)(struct rockchip_iodomain *iod); 67}; 68 69struct rockchip_iodomain_supply { 70 struct rockchip_iodomain *iod; 71 struct regulator *reg; 72 struct notifier_block nb; 73 int idx; 74}; 75 76struct rockchip_iodomain { 77 struct device *dev; 78 struct regmap *grf; 79 struct rockchip_iodomain_soc_data *soc_data; 80 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES]; 81}; 82 83static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply, 84 int uV) 85{ 86 struct rockchip_iodomain *iod = supply->iod; 87 u32 val; 88 int ret; 89 90 /* set value bit */ 91 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1; 92 val <<= supply->idx; 93 94 /* apply hiword-mask */ 95 val |= (BIT(supply->idx) << 16); 96 97 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val); 98 if (ret) 99 dev_err(iod->dev, "Couldn't write to GRF\n"); 100 101 return ret; 102} 103 104static int rockchip_iodomain_notify(struct notifier_block *nb, 105 unsigned long event, 106 void *data) 107{ 108 struct rockchip_iodomain_supply *supply = 109 container_of(nb, struct rockchip_iodomain_supply, nb); 110 int uV; 111 int ret; 112 113 /* 114 * According to Rockchip it's important to keep the SoC IO domain 115 * higher than (or equal to) the external voltage. That means we need 116 * to change it before external voltage changes happen in the case 117 * of an increase. 118 * 119 * Note that in the "pre" change we pick the max possible voltage that 120 * the regulator might end up at (the client requests a range and we 121 * don't know for certain the exact voltage). Right now we rely on the 122 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients 123 * request something like a max of 3.6V when they really want 3.3V. 124 * We could attempt to come up with better rules if this fails. 125 */ 126 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { 127 struct pre_voltage_change_data *pvc_data = data; 128 129 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV); 130 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE | 131 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) { 132 uV = (unsigned long)data; 133 } else { 134 return NOTIFY_OK; 135 } 136 137 dev_dbg(supply->iod->dev, "Setting to %d\n", uV); 138 139 if (uV > MAX_VOLTAGE_3_3) { 140 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV); 141 142 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 143 return NOTIFY_BAD; 144 } 145 146 ret = rockchip_iodomain_write(supply, uV); 147 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 148 return NOTIFY_BAD; 149 150 dev_dbg(supply->iod->dev, "Setting to %d done\n", uV); 151 return NOTIFY_OK; 152} 153 154static void rk3288_iodomain_init(struct rockchip_iodomain *iod) 155{ 156 int ret; 157 u32 val; 158 159 /* if no flash supply we should leave things alone */ 160 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg) 161 return; 162 163 /* 164 * set flash0 iodomain to also use this framework 165 * instead of a special gpio. 166 */ 167 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16); 168 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val); 169 if (ret < 0) 170 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 171} 172 173static void rk3328_iodomain_init(struct rockchip_iodomain *iod) 174{ 175 int ret; 176 u32 val; 177 178 /* if no vccio2 supply we should leave things alone */ 179 if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg) 180 return; 181 182 /* 183 * set vccio2 iodomain to also use this framework 184 * instead of a special gpio. 185 */ 186 val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16); 187 ret = regmap_write(iod->grf, RK3328_SOC_CON4, val); 188 if (ret < 0) 189 dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n"); 190} 191 192static void rk3368_iodomain_init(struct rockchip_iodomain *iod) 193{ 194 int ret; 195 u32 val; 196 197 /* if no flash supply we should leave things alone */ 198 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg) 199 return; 200 201 /* 202 * set flash0 iodomain to also use this framework 203 * instead of a special gpio. 204 */ 205 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16); 206 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val); 207 if (ret < 0) 208 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 209} 210 211static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod) 212{ 213 int ret; 214 u32 val; 215 216 /* if no pmu io supply we should leave things alone */ 217 if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg) 218 return; 219 220 /* 221 * set pmu io iodomain to also use this framework 222 * instead of a special gpio. 223 */ 224 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16); 225 ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val); 226 if (ret < 0) 227 dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n"); 228} 229 230/* 231 * On the rk3188 the io-domains are handled by a shared register with the 232 * lower 8 bits being still being continuing drive-strength settings. 233 */ 234static const struct rockchip_iodomain_soc_data soc_data_rk3188 = { 235 .grf_offset = 0x104, 236 .supply_names = { 237 NULL, 238 NULL, 239 NULL, 240 NULL, 241 NULL, 242 NULL, 243 NULL, 244 NULL, 245 "ap0", 246 "ap1", 247 "cif", 248 "flash", 249 "vccio0", 250 "vccio1", 251 "lcdc0", 252 "lcdc1", 253 }, 254}; 255 256static const struct rockchip_iodomain_soc_data soc_data_rk3228 = { 257 .grf_offset = 0x418, 258 .supply_names = { 259 "vccio1", 260 "vccio2", 261 "vccio3", 262 "vccio4", 263 }, 264}; 265 266static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { 267 .grf_offset = 0x380, 268 .supply_names = { 269 "lcdc", /* LCDC_VDD */ 270 "dvp", /* DVPIO_VDD */ 271 "flash0", /* FLASH0_VDD (emmc) */ 272 "flash1", /* FLASH1_VDD (sdio1) */ 273 "wifi", /* APIO3_VDD (sdio0) */ 274 "bb", /* APIO5_VDD */ 275 "audio", /* APIO4_VDD */ 276 "sdcard", /* SDMMC0_VDD (sdmmc) */ 277 "gpio30", /* APIO1_VDD */ 278 "gpio1830", /* APIO2_VDD */ 279 }, 280 .init = rk3288_iodomain_init, 281}; 282 283static const struct rockchip_iodomain_soc_data soc_data_rk3328 = { 284 .grf_offset = 0x410, 285 .supply_names = { 286 "vccio1", 287 "vccio2", 288 "vccio3", 289 "vccio4", 290 "vccio5", 291 "vccio6", 292 "pmuio", 293 }, 294 .init = rk3328_iodomain_init, 295}; 296 297static const struct rockchip_iodomain_soc_data soc_data_rk3368 = { 298 .grf_offset = 0x900, 299 .supply_names = { 300 NULL, /* reserved */ 301 "dvp", /* DVPIO_VDD */ 302 "flash0", /* FLASH0_VDD (emmc) */ 303 "wifi", /* APIO2_VDD (sdio0) */ 304 NULL, 305 "audio", /* APIO3_VDD */ 306 "sdcard", /* SDMMC0_VDD (sdmmc) */ 307 "gpio30", /* APIO1_VDD */ 308 "gpio1830", /* APIO4_VDD (gpujtag) */ 309 }, 310 .init = rk3368_iodomain_init, 311}; 312 313static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = { 314 .grf_offset = 0x100, 315 .supply_names = { 316 NULL, 317 NULL, 318 NULL, 319 NULL, 320 "pmu", /*PMU IO domain*/ 321 "vop", /*LCDC IO domain*/ 322 }, 323}; 324 325static const struct rockchip_iodomain_soc_data soc_data_rk3399 = { 326 .grf_offset = 0xe640, 327 .supply_names = { 328 "bt656", /* APIO2_VDD */ 329 "audio", /* APIO5_VDD */ 330 "sdmmc", /* SDMMC0_VDD */ 331 "gpio1830", /* APIO4_VDD */ 332 }, 333}; 334 335static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = { 336 .grf_offset = 0x180, 337 .supply_names = { 338 NULL, 339 NULL, 340 NULL, 341 NULL, 342 NULL, 343 NULL, 344 NULL, 345 NULL, 346 NULL, 347 "pmu1830", /* PMUIO2_VDD */ 348 }, 349 .init = rk3399_pmu_iodomain_init, 350}; 351 352static const struct of_device_id rockchip_iodomain_match[] = { 353 { 354 .compatible = "rockchip,rk3188-io-voltage-domain", 355 .data = (void *)&soc_data_rk3188 356 }, 357 { 358 .compatible = "rockchip,rk3228-io-voltage-domain", 359 .data = (void *)&soc_data_rk3228 360 }, 361 { 362 .compatible = "rockchip,rk3288-io-voltage-domain", 363 .data = (void *)&soc_data_rk3288 364 }, 365 { 366 .compatible = "rockchip,rk3328-io-voltage-domain", 367 .data = (void *)&soc_data_rk3328 368 }, 369 { 370 .compatible = "rockchip,rk3368-io-voltage-domain", 371 .data = (void *)&soc_data_rk3368 372 }, 373 { 374 .compatible = "rockchip,rk3368-pmu-io-voltage-domain", 375 .data = (void *)&soc_data_rk3368_pmu 376 }, 377 { 378 .compatible = "rockchip,rk3399-io-voltage-domain", 379 .data = (void *)&soc_data_rk3399 380 }, 381 { 382 .compatible = "rockchip,rk3399-pmu-io-voltage-domain", 383 .data = (void *)&soc_data_rk3399_pmu 384 }, 385 { /* sentinel */ }, 386}; 387MODULE_DEVICE_TABLE(of, rockchip_iodomain_match); 388 389static int rockchip_iodomain_probe(struct platform_device *pdev) 390{ 391 struct device_node *np = pdev->dev.of_node; 392 const struct of_device_id *match; 393 struct rockchip_iodomain *iod; 394 struct device *parent; 395 int i, ret = 0; 396 397 if (!np) 398 return -ENODEV; 399 400 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL); 401 if (!iod) 402 return -ENOMEM; 403 404 iod->dev = &pdev->dev; 405 platform_set_drvdata(pdev, iod); 406 407 match = of_match_node(rockchip_iodomain_match, np); 408 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data; 409 410 parent = pdev->dev.parent; 411 if (parent && parent->of_node) { 412 iod->grf = syscon_node_to_regmap(parent->of_node); 413 } else { 414 dev_dbg(&pdev->dev, "falling back to old binding\n"); 415 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 416 } 417 418 if (IS_ERR(iod->grf)) { 419 dev_err(&pdev->dev, "couldn't find grf regmap\n"); 420 return PTR_ERR(iod->grf); 421 } 422 423 for (i = 0; i < MAX_SUPPLIES; i++) { 424 const char *supply_name = iod->soc_data->supply_names[i]; 425 struct rockchip_iodomain_supply *supply = &iod->supplies[i]; 426 struct regulator *reg; 427 int uV; 428 429 if (!supply_name) 430 continue; 431 432 reg = devm_regulator_get_optional(iod->dev, supply_name); 433 if (IS_ERR(reg)) { 434 ret = PTR_ERR(reg); 435 436 /* If a supply wasn't specified, that's OK */ 437 if (ret == -ENODEV) 438 continue; 439 else if (ret != -EPROBE_DEFER) 440 dev_err(iod->dev, "couldn't get regulator %s\n", 441 supply_name); 442 goto unreg_notify; 443 } 444 445 /* set initial correct value */ 446 uV = regulator_get_voltage(reg); 447 448 /* must be a regulator we can get the voltage of */ 449 if (uV < 0) { 450 dev_err(iod->dev, "Can't determine voltage: %s\n", 451 supply_name); 452 goto unreg_notify; 453 } 454 455 if (uV > MAX_VOLTAGE_3_3) { 456 dev_crit(iod->dev, 457 "%d uV is too high. May damage SoC!\n", 458 uV); 459 ret = -EINVAL; 460 goto unreg_notify; 461 } 462 463 /* setup our supply */ 464 supply->idx = i; 465 supply->iod = iod; 466 supply->reg = reg; 467 supply->nb.notifier_call = rockchip_iodomain_notify; 468 469 ret = rockchip_iodomain_write(supply, uV); 470 if (ret) { 471 supply->reg = NULL; 472 goto unreg_notify; 473 } 474 475 /* register regulator notifier */ 476 ret = regulator_register_notifier(reg, &supply->nb); 477 if (ret) { 478 dev_err(&pdev->dev, 479 "regulator notifier request failed\n"); 480 supply->reg = NULL; 481 goto unreg_notify; 482 } 483 } 484 485 if (iod->soc_data->init) 486 iod->soc_data->init(iod); 487 488 return 0; 489 490unreg_notify: 491 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 492 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 493 494 if (io_supply->reg) 495 regulator_unregister_notifier(io_supply->reg, 496 &io_supply->nb); 497 } 498 499 return ret; 500} 501 502static int rockchip_iodomain_remove(struct platform_device *pdev) 503{ 504 struct rockchip_iodomain *iod = platform_get_drvdata(pdev); 505 int i; 506 507 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 508 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 509 510 if (io_supply->reg) 511 regulator_unregister_notifier(io_supply->reg, 512 &io_supply->nb); 513 } 514 515 return 0; 516} 517 518static struct platform_driver rockchip_iodomain_driver = { 519 .probe = rockchip_iodomain_probe, 520 .remove = rockchip_iodomain_remove, 521 .driver = { 522 .name = "rockchip-iodomain", 523 .of_match_table = rockchip_iodomain_match, 524 }, 525}; 526 527module_platform_driver(rockchip_iodomain_driver); 528 529MODULE_DESCRIPTION("Rockchip IO-domain driver"); 530MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 531MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>"); 532MODULE_LICENSE("GPL v2");