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 
50 struct rockchip_iodomain;
51 
52 /**
53  * @supplies: voltage settings matching the register bits.
54  */
55 struct rockchip_iodomain_soc_data {
56 	int grf_offset;
57 	const char *supply_names[MAX_SUPPLIES];
58 	void (*init)(struct rockchip_iodomain *iod);
59 };
60 
61 struct rockchip_iodomain_supply {
62 	struct rockchip_iodomain *iod;
63 	struct regulator *reg;
64 	struct notifier_block nb;
65 	int idx;
66 };
67 
68 struct 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 
rockchip_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)75 static 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 
rockchip_iodomain_notify(struct notifier_block * nb,unsigned long event,void * data)96 static 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 
rk3288_iodomain_init(struct rockchip_iodomain * iod)146 static 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 
rk3368_iodomain_init(struct rockchip_iodomain * iod)165 static 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  */
188 static 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 
210 static 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 
227 static 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 
243 static 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 
255 static 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 };
274 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
275 
rockchip_iodomain_probe(struct platform_device * pdev)276 static 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 
369 unreg_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 
rockchip_iodomain_remove(struct platform_device * pdev)381 static 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 
397 static 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 
406 module_platform_driver(rockchip_iodomain_driver);
407 
408 MODULE_DESCRIPTION("Rockchip IO-domain driver");
409 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
410 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
411 MODULE_LICENSE("GPL v2");
412