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 46struct rockchip_iodomain; 47 48/** 49 * @supplies: voltage settings matching the register bits. 50 */ 51struct rockchip_iodomain_soc_data { 52 int grf_offset; 53 const char *supply_names[MAX_SUPPLIES]; 54 void (*init)(struct rockchip_iodomain *iod); 55}; 56 57struct rockchip_iodomain_supply { 58 struct rockchip_iodomain *iod; 59 struct regulator *reg; 60 struct notifier_block nb; 61 int idx; 62}; 63 64struct rockchip_iodomain { 65 struct device *dev; 66 struct regmap *grf; 67 struct rockchip_iodomain_soc_data *soc_data; 68 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES]; 69}; 70 71static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply, 72 int uV) 73{ 74 struct rockchip_iodomain *iod = supply->iod; 75 u32 val; 76 int ret; 77 78 /* set value bit */ 79 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1; 80 val <<= supply->idx; 81 82 /* apply hiword-mask */ 83 val |= (BIT(supply->idx) << 16); 84 85 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val); 86 if (ret) 87 dev_err(iod->dev, "Couldn't write to GRF\n"); 88 89 return ret; 90} 91 92static int rockchip_iodomain_notify(struct notifier_block *nb, 93 unsigned long event, 94 void *data) 95{ 96 struct rockchip_iodomain_supply *supply = 97 container_of(nb, struct rockchip_iodomain_supply, nb); 98 int uV; 99 int ret; 100 101 /* 102 * According to Rockchip it's important to keep the SoC IO domain 103 * higher than (or equal to) the external voltage. That means we need 104 * to change it before external voltage changes happen in the case 105 * of an increase. 106 * 107 * Note that in the "pre" change we pick the max possible voltage that 108 * the regulator might end up at (the client requests a range and we 109 * don't know for certain the exact voltage). Right now we rely on the 110 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients 111 * request something like a max of 3.6V when they really want 3.3V. 112 * We could attempt to come up with better rules if this fails. 113 */ 114 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { 115 struct pre_voltage_change_data *pvc_data = data; 116 117 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV); 118 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE | 119 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) { 120 uV = (unsigned long)data; 121 } else { 122 return NOTIFY_OK; 123 } 124 125 dev_dbg(supply->iod->dev, "Setting to %d\n", uV); 126 127 if (uV > MAX_VOLTAGE_3_3) { 128 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV); 129 130 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 131 return NOTIFY_BAD; 132 } 133 134 ret = rockchip_iodomain_write(supply, uV); 135 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) 136 return NOTIFY_BAD; 137 138 dev_info(supply->iod->dev, "Setting to %d done\n", uV); 139 return NOTIFY_OK; 140} 141 142static void rk3288_iodomain_init(struct rockchip_iodomain *iod) 143{ 144 int ret; 145 u32 val; 146 147 /* if no flash supply we should leave things alone */ 148 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg) 149 return; 150 151 /* 152 * set flash0 iodomain to also use this framework 153 * instead of a special gpio. 154 */ 155 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16); 156 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val); 157 if (ret < 0) 158 dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); 159} 160 161/* 162 * On the rk3188 the io-domains are handled by a shared register with the 163 * lower 8 bits being still being continuing drive-strength settings. 164 */ 165static const struct rockchip_iodomain_soc_data soc_data_rk3188 = { 166 .grf_offset = 0x104, 167 .supply_names = { 168 NULL, 169 NULL, 170 NULL, 171 NULL, 172 NULL, 173 NULL, 174 NULL, 175 NULL, 176 "ap0", 177 "ap1", 178 "cif", 179 "flash", 180 "vccio0", 181 "vccio1", 182 "lcdc0", 183 "lcdc1", 184 }, 185}; 186 187static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { 188 .grf_offset = 0x380, 189 .supply_names = { 190 "lcdc", /* LCDC_VDD */ 191 "dvp", /* DVPIO_VDD */ 192 "flash0", /* FLASH0_VDD (emmc) */ 193 "flash1", /* FLASH1_VDD (sdio1) */ 194 "wifi", /* APIO3_VDD (sdio0) */ 195 "bb", /* APIO5_VDD */ 196 "audio", /* APIO4_VDD */ 197 "sdcard", /* SDMMC0_VDD (sdmmc) */ 198 "gpio30", /* APIO1_VDD */ 199 "gpio1830", /* APIO2_VDD */ 200 }, 201 .init = rk3288_iodomain_init, 202}; 203 204static const struct of_device_id rockchip_iodomain_match[] = { 205 { 206 .compatible = "rockchip,rk3188-io-voltage-domain", 207 .data = (void *)&soc_data_rk3188 208 }, 209 { 210 .compatible = "rockchip,rk3288-io-voltage-domain", 211 .data = (void *)&soc_data_rk3288 212 }, 213 { /* sentinel */ }, 214}; 215 216static int rockchip_iodomain_probe(struct platform_device *pdev) 217{ 218 struct device_node *np = pdev->dev.of_node; 219 const struct of_device_id *match; 220 struct rockchip_iodomain *iod; 221 int i, ret = 0; 222 223 if (!np) 224 return -ENODEV; 225 226 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL); 227 if (!iod) 228 return -ENOMEM; 229 230 iod->dev = &pdev->dev; 231 platform_set_drvdata(pdev, iod); 232 233 match = of_match_node(rockchip_iodomain_match, np); 234 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data; 235 236 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 237 if (IS_ERR(iod->grf)) { 238 dev_err(&pdev->dev, "couldn't find grf regmap\n"); 239 return PTR_ERR(iod->grf); 240 } 241 242 for (i = 0; i < MAX_SUPPLIES; i++) { 243 const char *supply_name = iod->soc_data->supply_names[i]; 244 struct rockchip_iodomain_supply *supply = &iod->supplies[i]; 245 struct regulator *reg; 246 int uV; 247 248 if (!supply_name) 249 continue; 250 251 reg = devm_regulator_get_optional(iod->dev, supply_name); 252 if (IS_ERR(reg)) { 253 ret = PTR_ERR(reg); 254 255 /* If a supply wasn't specified, that's OK */ 256 if (ret == -ENODEV) 257 continue; 258 else if (ret != -EPROBE_DEFER) 259 dev_err(iod->dev, "couldn't get regulator %s\n", 260 supply_name); 261 goto unreg_notify; 262 } 263 264 /* set initial correct value */ 265 uV = regulator_get_voltage(reg); 266 267 /* must be a regulator we can get the voltage of */ 268 if (uV < 0) { 269 dev_err(iod->dev, "Can't determine voltage: %s\n", 270 supply_name); 271 goto unreg_notify; 272 } 273 274 if (uV > MAX_VOLTAGE_3_3) { 275 dev_crit(iod->dev, 276 "%d uV is too high. May damage SoC!\n", 277 uV); 278 ret = -EINVAL; 279 goto unreg_notify; 280 } 281 282 /* setup our supply */ 283 supply->idx = i; 284 supply->iod = iod; 285 supply->reg = reg; 286 supply->nb.notifier_call = rockchip_iodomain_notify; 287 288 ret = rockchip_iodomain_write(supply, uV); 289 if (ret) { 290 supply->reg = NULL; 291 goto unreg_notify; 292 } 293 294 /* register regulator notifier */ 295 ret = regulator_register_notifier(reg, &supply->nb); 296 if (ret) { 297 dev_err(&pdev->dev, 298 "regulator notifier request failed\n"); 299 supply->reg = NULL; 300 goto unreg_notify; 301 } 302 } 303 304 if (iod->soc_data->init) 305 iod->soc_data->init(iod); 306 307 return 0; 308 309unreg_notify: 310 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 311 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 312 313 if (io_supply->reg) 314 regulator_unregister_notifier(io_supply->reg, 315 &io_supply->nb); 316 } 317 318 return ret; 319} 320 321static int rockchip_iodomain_remove(struct platform_device *pdev) 322{ 323 struct rockchip_iodomain *iod = platform_get_drvdata(pdev); 324 int i; 325 326 for (i = MAX_SUPPLIES - 1; i >= 0; i--) { 327 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i]; 328 329 if (io_supply->reg) 330 regulator_unregister_notifier(io_supply->reg, 331 &io_supply->nb); 332 } 333 334 return 0; 335} 336 337static struct platform_driver rockchip_iodomain_driver = { 338 .probe = rockchip_iodomain_probe, 339 .remove = rockchip_iodomain_remove, 340 .driver = { 341 .name = "rockchip-iodomain", 342 .of_match_table = rockchip_iodomain_match, 343 }, 344}; 345 346module_platform_driver(rockchip_iodomain_driver); 347 348MODULE_DESCRIPTION("Rockchip IO-domain driver"); 349MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 350MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>"); 351MODULE_LICENSE("GPL v2"); 352