[go: nahoru, domu]

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