blob: 2e300028f0f774d4662546ba0bd88cce32465cf2 [file] [log] [blame]
Heiko Stübner662a9582014-09-11 15:48:55 -07001/*
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
Heiko Stuebner3fc147e2015-08-04 21:37:01 +020046#define RK3368_SOC_CON15 0x43c
47#define RK3368_SOC_CON15_FLASH0 BIT(14)
48#define RK3368_SOC_FLASH_SUPPLY_NUM 2
49
Heiko Stübner662a9582014-09-11 15:48:55 -070050struct 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
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200165static 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
Heiko Stübner662a9582014-09-11 15:48:55 -0700184/*
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
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200227static 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
Heiko Stübner662a9582014-09-11 15:48:55 -0700255static 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 },
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200264 {
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 },
Heiko Stübner662a9582014-09-11 15:48:55 -0700272 { /* sentinel */ },
273};
274
275static int rockchip_iodomain_probe(struct platform_device *pdev)
276{
277 struct device_node *np = pdev->dev.of_node;
278 const struct of_device_id *match;
279 struct rockchip_iodomain *iod;
280 int i, ret = 0;
281
282 if (!np)
283 return -ENODEV;
284
285 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
286 if (!iod)
287 return -ENOMEM;
288
289 iod->dev = &pdev->dev;
290 platform_set_drvdata(pdev, iod);
291
292 match = of_match_node(rockchip_iodomain_match, np);
293 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data;
294
295 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
296 if (IS_ERR(iod->grf)) {
297 dev_err(&pdev->dev, "couldn't find grf regmap\n");
298 return PTR_ERR(iod->grf);
299 }
300
301 for (i = 0; i < MAX_SUPPLIES; i++) {
302 const char *supply_name = iod->soc_data->supply_names[i];
303 struct rockchip_iodomain_supply *supply = &iod->supplies[i];
304 struct regulator *reg;
305 int uV;
306
307 if (!supply_name)
308 continue;
309
310 reg = devm_regulator_get_optional(iod->dev, supply_name);
311 if (IS_ERR(reg)) {
312 ret = PTR_ERR(reg);
313
314 /* If a supply wasn't specified, that's OK */
315 if (ret == -ENODEV)
316 continue;
317 else if (ret != -EPROBE_DEFER)
318 dev_err(iod->dev, "couldn't get regulator %s\n",
319 supply_name);
320 goto unreg_notify;
321 }
322
323 /* set initial correct value */
324 uV = regulator_get_voltage(reg);
325
326 /* must be a regulator we can get the voltage of */
327 if (uV < 0) {
328 dev_err(iod->dev, "Can't determine voltage: %s\n",
329 supply_name);
330 goto unreg_notify;
331 }
332
333 if (uV > MAX_VOLTAGE_3_3) {
334 dev_crit(iod->dev,
335 "%d uV is too high. May damage SoC!\n",
336 uV);
337 ret = -EINVAL;
338 goto unreg_notify;
339 }
340
341 /* setup our supply */
342 supply->idx = i;
343 supply->iod = iod;
344 supply->reg = reg;
345 supply->nb.notifier_call = rockchip_iodomain_notify;
346
347 ret = rockchip_iodomain_write(supply, uV);
348 if (ret) {
349 supply->reg = NULL;
350 goto unreg_notify;
351 }
352
353 /* register regulator notifier */
354 ret = regulator_register_notifier(reg, &supply->nb);
355 if (ret) {
356 dev_err(&pdev->dev,
357 "regulator notifier request failed\n");
358 supply->reg = NULL;
359 goto unreg_notify;
360 }
361 }
362
363 if (iod->soc_data->init)
364 iod->soc_data->init(iod);
365
366 return 0;
367
368unreg_notify:
369 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
370 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
371
372 if (io_supply->reg)
373 regulator_unregister_notifier(io_supply->reg,
374 &io_supply->nb);
375 }
376
377 return ret;
378}
379
380static int rockchip_iodomain_remove(struct platform_device *pdev)
381{
382 struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
383 int i;
384
385 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
386 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
387
388 if (io_supply->reg)
389 regulator_unregister_notifier(io_supply->reg,
390 &io_supply->nb);
391 }
392
393 return 0;
394}
395
396static struct platform_driver rockchip_iodomain_driver = {
397 .probe = rockchip_iodomain_probe,
398 .remove = rockchip_iodomain_remove,
399 .driver = {
400 .name = "rockchip-iodomain",
401 .of_match_table = rockchip_iodomain_match,
402 },
403};
404
405module_platform_driver(rockchip_iodomain_driver);
406
407MODULE_DESCRIPTION("Rockchip IO-domain driver");
408MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
409MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
410MODULE_LICENSE("GPL v2");