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