1e943c43bSUlf Hansson // SPDX-License-Identifier: GPL-2.0-only
2e943c43bSUlf Hansson /*
3e943c43bSUlf Hansson * Rockchip IO Voltage Domain driver
4e943c43bSUlf Hansson *
5e943c43bSUlf Hansson * Copyright 2014 MundoReader S.L.
6e943c43bSUlf Hansson * Copyright 2014 Google, Inc.
7e943c43bSUlf Hansson */
8e943c43bSUlf Hansson
9e943c43bSUlf Hansson #include <linux/kernel.h>
10e943c43bSUlf Hansson #include <linux/module.h>
11e943c43bSUlf Hansson #include <linux/err.h>
12e943c43bSUlf Hansson #include <linux/mfd/syscon.h>
13e943c43bSUlf Hansson #include <linux/of.h>
14e943c43bSUlf Hansson #include <linux/platform_device.h>
15e943c43bSUlf Hansson #include <linux/regmap.h>
16e943c43bSUlf Hansson #include <linux/regulator/consumer.h>
17e943c43bSUlf Hansson
18e943c43bSUlf Hansson #define MAX_SUPPLIES 16
19e943c43bSUlf Hansson
20e943c43bSUlf Hansson /*
21e943c43bSUlf Hansson * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
22e943c43bSUlf Hansson * "Recommended Operating Conditions" for "Digital GPIO". When the typical
23e943c43bSUlf Hansson * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
24e943c43bSUlf Hansson *
25e943c43bSUlf Hansson * They are used like this:
26e943c43bSUlf Hansson * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
27e943c43bSUlf Hansson * SoC we're at 3.3.
28e943c43bSUlf Hansson * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
29e943c43bSUlf Hansson * that to be an error.
30e943c43bSUlf Hansson */
31e943c43bSUlf Hansson #define MAX_VOLTAGE_1_8 1980000
32e943c43bSUlf Hansson #define MAX_VOLTAGE_3_3 3600000
33e943c43bSUlf Hansson
34e943c43bSUlf Hansson #define PX30_IO_VSEL 0x180
35e943c43bSUlf Hansson #define PX30_IO_VSEL_VCCIO6_SRC BIT(0)
36e943c43bSUlf Hansson #define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1
37e943c43bSUlf Hansson
38e943c43bSUlf Hansson #define RK3288_SOC_CON2 0x24c
39e943c43bSUlf Hansson #define RK3288_SOC_CON2_FLASH0 BIT(7)
40e943c43bSUlf Hansson #define RK3288_SOC_FLASH_SUPPLY_NUM 2
41e943c43bSUlf Hansson
42*f0d70478SDavid Wu #define RK3308_SOC_CON0 0x300
43*f0d70478SDavid Wu #define RK3308_SOC_CON0_VCCIO3 BIT(8)
44*f0d70478SDavid Wu #define RK3308_SOC_VCCIO3_SUPPLY_NUM 3
45*f0d70478SDavid Wu
46e943c43bSUlf Hansson #define RK3328_SOC_CON4 0x410
47e943c43bSUlf Hansson #define RK3328_SOC_CON4_VCCIO2 BIT(7)
48e943c43bSUlf Hansson #define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
49e943c43bSUlf Hansson
50e943c43bSUlf Hansson #define RK3368_SOC_CON15 0x43c
51e943c43bSUlf Hansson #define RK3368_SOC_CON15_FLASH0 BIT(14)
52e943c43bSUlf Hansson #define RK3368_SOC_FLASH_SUPPLY_NUM 2
53e943c43bSUlf Hansson
54e943c43bSUlf Hansson #define RK3399_PMUGRF_CON0 0x180
55e943c43bSUlf Hansson #define RK3399_PMUGRF_CON0_VSEL BIT(8)
56e943c43bSUlf Hansson #define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9
57e943c43bSUlf Hansson
5828b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL0 (0x0140)
5928b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL1 (0x0144)
6028b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL2 (0x0148)
61e943c43bSUlf Hansson
6228b05a64SJianqun Xu struct rockchip_iodomain;
63e943c43bSUlf Hansson
64e943c43bSUlf Hansson struct rockchip_iodomain_supply {
65e943c43bSUlf Hansson struct rockchip_iodomain *iod;
66e943c43bSUlf Hansson struct regulator *reg;
67e943c43bSUlf Hansson struct notifier_block nb;
68e943c43bSUlf Hansson int idx;
69e943c43bSUlf Hansson };
70e943c43bSUlf Hansson
7128b05a64SJianqun Xu struct rockchip_iodomain_soc_data {
7228b05a64SJianqun Xu int grf_offset;
7328b05a64SJianqun Xu const char *supply_names[MAX_SUPPLIES];
7428b05a64SJianqun Xu void (*init)(struct rockchip_iodomain *iod);
7528b05a64SJianqun Xu int (*write)(struct rockchip_iodomain_supply *supply, int uV);
7628b05a64SJianqun Xu };
7728b05a64SJianqun Xu
78e943c43bSUlf Hansson struct rockchip_iodomain {
79e943c43bSUlf Hansson struct device *dev;
80e943c43bSUlf Hansson struct regmap *grf;
81e943c43bSUlf Hansson const struct rockchip_iodomain_soc_data *soc_data;
82e943c43bSUlf Hansson struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
8328b05a64SJianqun Xu int (*write)(struct rockchip_iodomain_supply *supply, int uV);
84e943c43bSUlf Hansson };
85e943c43bSUlf Hansson
rk3568_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)8628b05a64SJianqun Xu static int rk3568_iodomain_write(struct rockchip_iodomain_supply *supply, int uV)
8728b05a64SJianqun Xu {
8828b05a64SJianqun Xu struct rockchip_iodomain *iod = supply->iod;
8928b05a64SJianqun Xu u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
9028b05a64SJianqun Xu u32 val0, val1;
9128b05a64SJianqun Xu int b;
9228b05a64SJianqun Xu
9328b05a64SJianqun Xu switch (supply->idx) {
9428b05a64SJianqun Xu case 0: /* pmuio1 */
9528b05a64SJianqun Xu break;
9628b05a64SJianqun Xu case 1: /* pmuio2 */
9728b05a64SJianqun Xu b = supply->idx;
9828b05a64SJianqun Xu val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
9928b05a64SJianqun Xu b = supply->idx + 4;
10028b05a64SJianqun Xu val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
10128b05a64SJianqun Xu
10228b05a64SJianqun Xu regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val0);
10328b05a64SJianqun Xu regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val1);
10428b05a64SJianqun Xu break;
10528b05a64SJianqun Xu case 3: /* vccio2 */
10628b05a64SJianqun Xu break;
10728b05a64SJianqun Xu case 2: /* vccio1 */
10828b05a64SJianqun Xu case 4: /* vccio3 */
10928b05a64SJianqun Xu case 5: /* vccio4 */
11028b05a64SJianqun Xu case 6: /* vccio5 */
11128b05a64SJianqun Xu case 7: /* vccio6 */
11228b05a64SJianqun Xu case 8: /* vccio7 */
11328b05a64SJianqun Xu b = supply->idx - 1;
11428b05a64SJianqun Xu val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
11528b05a64SJianqun Xu val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
11628b05a64SJianqun Xu
11728b05a64SJianqun Xu regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL0, val0);
11828b05a64SJianqun Xu regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL1, val1);
11928b05a64SJianqun Xu break;
12028b05a64SJianqun Xu default:
12128b05a64SJianqun Xu return -EINVAL;
1229e5747c5SJiapeng Chong }
12328b05a64SJianqun Xu
12428b05a64SJianqun Xu return 0;
12528b05a64SJianqun Xu }
12628b05a64SJianqun Xu
rockchip_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)127e943c43bSUlf Hansson static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
128e943c43bSUlf Hansson int uV)
129e943c43bSUlf Hansson {
130e943c43bSUlf Hansson struct rockchip_iodomain *iod = supply->iod;
131e943c43bSUlf Hansson u32 val;
132e943c43bSUlf Hansson int ret;
133e943c43bSUlf Hansson
134e943c43bSUlf Hansson /* set value bit */
135e943c43bSUlf Hansson val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
136e943c43bSUlf Hansson val <<= supply->idx;
137e943c43bSUlf Hansson
138e943c43bSUlf Hansson /* apply hiword-mask */
139e943c43bSUlf Hansson val |= (BIT(supply->idx) << 16);
140e943c43bSUlf Hansson
141e943c43bSUlf Hansson ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
142e943c43bSUlf Hansson if (ret)
143e943c43bSUlf Hansson dev_err(iod->dev, "Couldn't write to GRF\n");
144e943c43bSUlf Hansson
145e943c43bSUlf Hansson return ret;
146e943c43bSUlf Hansson }
147e943c43bSUlf Hansson
rockchip_iodomain_notify(struct notifier_block * nb,unsigned long event,void * data)148e943c43bSUlf Hansson static int rockchip_iodomain_notify(struct notifier_block *nb,
149e943c43bSUlf Hansson unsigned long event,
150e943c43bSUlf Hansson void *data)
151e943c43bSUlf Hansson {
152e943c43bSUlf Hansson struct rockchip_iodomain_supply *supply =
153e943c43bSUlf Hansson container_of(nb, struct rockchip_iodomain_supply, nb);
154e943c43bSUlf Hansson int uV;
155e943c43bSUlf Hansson int ret;
156e943c43bSUlf Hansson
157e943c43bSUlf Hansson /*
158e943c43bSUlf Hansson * According to Rockchip it's important to keep the SoC IO domain
159e943c43bSUlf Hansson * higher than (or equal to) the external voltage. That means we need
160e943c43bSUlf Hansson * to change it before external voltage changes happen in the case
161e943c43bSUlf Hansson * of an increase.
162e943c43bSUlf Hansson *
163e943c43bSUlf Hansson * Note that in the "pre" change we pick the max possible voltage that
164e943c43bSUlf Hansson * the regulator might end up at (the client requests a range and we
165e943c43bSUlf Hansson * don't know for certain the exact voltage). Right now we rely on the
166e943c43bSUlf Hansson * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
167e943c43bSUlf Hansson * request something like a max of 3.6V when they really want 3.3V.
168e943c43bSUlf Hansson * We could attempt to come up with better rules if this fails.
169e943c43bSUlf Hansson */
170e943c43bSUlf Hansson if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
171e943c43bSUlf Hansson struct pre_voltage_change_data *pvc_data = data;
172e943c43bSUlf Hansson
173e943c43bSUlf Hansson uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
174e943c43bSUlf Hansson } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
175e943c43bSUlf Hansson REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
176e943c43bSUlf Hansson uV = (unsigned long)data;
177e943c43bSUlf Hansson } else {
178e943c43bSUlf Hansson return NOTIFY_OK;
179e943c43bSUlf Hansson }
180e943c43bSUlf Hansson
181e943c43bSUlf Hansson dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
182e943c43bSUlf Hansson
183e943c43bSUlf Hansson if (uV > MAX_VOLTAGE_3_3) {
184e943c43bSUlf Hansson dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
185e943c43bSUlf Hansson
186e943c43bSUlf Hansson if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
187e943c43bSUlf Hansson return NOTIFY_BAD;
188e943c43bSUlf Hansson }
189e943c43bSUlf Hansson
19028b05a64SJianqun Xu ret = supply->iod->write(supply, uV);
191e943c43bSUlf Hansson if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
192e943c43bSUlf Hansson return NOTIFY_BAD;
193e943c43bSUlf Hansson
194e943c43bSUlf Hansson dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
195e943c43bSUlf Hansson return NOTIFY_OK;
196e943c43bSUlf Hansson }
197e943c43bSUlf Hansson
px30_iodomain_init(struct rockchip_iodomain * iod)198e943c43bSUlf Hansson static void px30_iodomain_init(struct rockchip_iodomain *iod)
199e943c43bSUlf Hansson {
200e943c43bSUlf Hansson int ret;
201e943c43bSUlf Hansson u32 val;
202e943c43bSUlf Hansson
203e943c43bSUlf Hansson /* if no VCCIO6 supply we should leave things alone */
204e943c43bSUlf Hansson if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
205e943c43bSUlf Hansson return;
206e943c43bSUlf Hansson
207e943c43bSUlf Hansson /*
208e943c43bSUlf Hansson * set vccio6 iodomain to also use this framework
209e943c43bSUlf Hansson * instead of a special gpio.
210e943c43bSUlf Hansson */
211e943c43bSUlf Hansson val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
212e943c43bSUlf Hansson ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
213e943c43bSUlf Hansson if (ret < 0)
214e943c43bSUlf Hansson dev_warn(iod->dev, "couldn't update vccio6 ctrl\n");
215e943c43bSUlf Hansson }
216e943c43bSUlf Hansson
rk3288_iodomain_init(struct rockchip_iodomain * iod)217e943c43bSUlf Hansson static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
218e943c43bSUlf Hansson {
219e943c43bSUlf Hansson int ret;
220e943c43bSUlf Hansson u32 val;
221e943c43bSUlf Hansson
222e943c43bSUlf Hansson /* if no flash supply we should leave things alone */
223e943c43bSUlf Hansson if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
224e943c43bSUlf Hansson return;
225e943c43bSUlf Hansson
226e943c43bSUlf Hansson /*
227e943c43bSUlf Hansson * set flash0 iodomain to also use this framework
228e943c43bSUlf Hansson * instead of a special gpio.
229e943c43bSUlf Hansson */
230e943c43bSUlf Hansson val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
231e943c43bSUlf Hansson ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
232e943c43bSUlf Hansson if (ret < 0)
233e943c43bSUlf Hansson dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
234e943c43bSUlf Hansson }
235e943c43bSUlf Hansson
rk3308_iodomain_init(struct rockchip_iodomain * iod)236*f0d70478SDavid Wu static void rk3308_iodomain_init(struct rockchip_iodomain *iod)
237*f0d70478SDavid Wu {
238*f0d70478SDavid Wu int ret;
239*f0d70478SDavid Wu u32 val;
240*f0d70478SDavid Wu
241*f0d70478SDavid Wu /* if no vccio3 supply we should leave things alone */
242*f0d70478SDavid Wu if (!iod->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg)
243*f0d70478SDavid Wu return;
244*f0d70478SDavid Wu
245*f0d70478SDavid Wu /*
246*f0d70478SDavid Wu * set vccio3 iodomain to also use this framework
247*f0d70478SDavid Wu * instead of a special gpio.
248*f0d70478SDavid Wu */
249*f0d70478SDavid Wu val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16);
250*f0d70478SDavid Wu ret = regmap_write(iod->grf, RK3308_SOC_CON0, val);
251*f0d70478SDavid Wu if (ret < 0)
252*f0d70478SDavid Wu dev_warn(iod->dev, "couldn't update vccio3 vsel ctrl\n");
253*f0d70478SDavid Wu }
254*f0d70478SDavid Wu
rk3328_iodomain_init(struct rockchip_iodomain * iod)255e943c43bSUlf Hansson static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
256e943c43bSUlf Hansson {
257e943c43bSUlf Hansson int ret;
258e943c43bSUlf Hansson u32 val;
259e943c43bSUlf Hansson
260e943c43bSUlf Hansson /* if no vccio2 supply we should leave things alone */
261e943c43bSUlf Hansson if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
262e943c43bSUlf Hansson return;
263e943c43bSUlf Hansson
264e943c43bSUlf Hansson /*
265e943c43bSUlf Hansson * set vccio2 iodomain to also use this framework
266e943c43bSUlf Hansson * instead of a special gpio.
267e943c43bSUlf Hansson */
268e943c43bSUlf Hansson val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
269e943c43bSUlf Hansson ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
270e943c43bSUlf Hansson if (ret < 0)
271e943c43bSUlf Hansson dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
272e943c43bSUlf Hansson }
273e943c43bSUlf Hansson
rk3368_iodomain_init(struct rockchip_iodomain * iod)274e943c43bSUlf Hansson static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
275e943c43bSUlf Hansson {
276e943c43bSUlf Hansson int ret;
277e943c43bSUlf Hansson u32 val;
278e943c43bSUlf Hansson
279e943c43bSUlf Hansson /* if no flash supply we should leave things alone */
280e943c43bSUlf Hansson if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
281e943c43bSUlf Hansson return;
282e943c43bSUlf Hansson
283e943c43bSUlf Hansson /*
284e943c43bSUlf Hansson * set flash0 iodomain to also use this framework
285e943c43bSUlf Hansson * instead of a special gpio.
286e943c43bSUlf Hansson */
287e943c43bSUlf Hansson val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
288e943c43bSUlf Hansson ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
289e943c43bSUlf Hansson if (ret < 0)
290e943c43bSUlf Hansson dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
291e943c43bSUlf Hansson }
292e943c43bSUlf Hansson
rk3399_pmu_iodomain_init(struct rockchip_iodomain * iod)293e943c43bSUlf Hansson static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
294e943c43bSUlf Hansson {
295e943c43bSUlf Hansson int ret;
296e943c43bSUlf Hansson u32 val;
297e943c43bSUlf Hansson
298e943c43bSUlf Hansson /* if no pmu io supply we should leave things alone */
299e943c43bSUlf Hansson if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
300e943c43bSUlf Hansson return;
301e943c43bSUlf Hansson
302e943c43bSUlf Hansson /*
303e943c43bSUlf Hansson * set pmu io iodomain to also use this framework
304e943c43bSUlf Hansson * instead of a special gpio.
305e943c43bSUlf Hansson */
306e943c43bSUlf Hansson val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
307e943c43bSUlf Hansson ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
308e943c43bSUlf Hansson if (ret < 0)
309e943c43bSUlf Hansson dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
310e943c43bSUlf Hansson }
311e943c43bSUlf Hansson
312e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_px30 = {
313e943c43bSUlf Hansson .grf_offset = 0x180,
314e943c43bSUlf Hansson .supply_names = {
315e943c43bSUlf Hansson NULL,
316e943c43bSUlf Hansson "vccio6",
317e943c43bSUlf Hansson "vccio1",
318e943c43bSUlf Hansson "vccio2",
319e943c43bSUlf Hansson "vccio3",
320e943c43bSUlf Hansson "vccio4",
321e943c43bSUlf Hansson "vccio5",
322e943c43bSUlf Hansson "vccio-oscgpi",
323e943c43bSUlf Hansson },
324e943c43bSUlf Hansson .init = px30_iodomain_init,
325e943c43bSUlf Hansson };
326e943c43bSUlf Hansson
327e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
328e943c43bSUlf Hansson .grf_offset = 0x100,
329e943c43bSUlf Hansson .supply_names = {
330e943c43bSUlf Hansson NULL,
331e943c43bSUlf Hansson NULL,
332e943c43bSUlf Hansson NULL,
333e943c43bSUlf Hansson NULL,
334e943c43bSUlf Hansson NULL,
335e943c43bSUlf Hansson NULL,
336e943c43bSUlf Hansson NULL,
337e943c43bSUlf Hansson NULL,
338e943c43bSUlf Hansson NULL,
339e943c43bSUlf Hansson NULL,
340e943c43bSUlf Hansson NULL,
341e943c43bSUlf Hansson NULL,
342e943c43bSUlf Hansson NULL,
343e943c43bSUlf Hansson NULL,
344e943c43bSUlf Hansson "pmuio1",
345e943c43bSUlf Hansson "pmuio2",
346e943c43bSUlf Hansson },
347e943c43bSUlf Hansson };
348e943c43bSUlf Hansson
349e943c43bSUlf Hansson /*
350e943c43bSUlf Hansson * On the rk3188 the io-domains are handled by a shared register with the
351e943c43bSUlf Hansson * lower 8 bits being still being continuing drive-strength settings.
352e943c43bSUlf Hansson */
353e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
354e943c43bSUlf Hansson .grf_offset = 0x104,
355e943c43bSUlf Hansson .supply_names = {
356e943c43bSUlf Hansson NULL,
357e943c43bSUlf Hansson NULL,
358e943c43bSUlf Hansson NULL,
359e943c43bSUlf Hansson NULL,
360e943c43bSUlf Hansson NULL,
361e943c43bSUlf Hansson NULL,
362e943c43bSUlf Hansson NULL,
363e943c43bSUlf Hansson NULL,
364e943c43bSUlf Hansson "ap0",
365e943c43bSUlf Hansson "ap1",
366e943c43bSUlf Hansson "cif",
367e943c43bSUlf Hansson "flash",
368e943c43bSUlf Hansson "vccio0",
369e943c43bSUlf Hansson "vccio1",
370e943c43bSUlf Hansson "lcdc0",
371e943c43bSUlf Hansson "lcdc1",
372e943c43bSUlf Hansson },
373e943c43bSUlf Hansson };
374e943c43bSUlf Hansson
375e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
376e943c43bSUlf Hansson .grf_offset = 0x418,
377e943c43bSUlf Hansson .supply_names = {
378e943c43bSUlf Hansson "vccio1",
379e943c43bSUlf Hansson "vccio2",
380e943c43bSUlf Hansson "vccio3",
381e943c43bSUlf Hansson "vccio4",
382e943c43bSUlf Hansson },
383e943c43bSUlf Hansson };
384e943c43bSUlf Hansson
385e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
386e943c43bSUlf Hansson .grf_offset = 0x380,
387e943c43bSUlf Hansson .supply_names = {
388e943c43bSUlf Hansson "lcdc", /* LCDC_VDD */
389e943c43bSUlf Hansson "dvp", /* DVPIO_VDD */
390e943c43bSUlf Hansson "flash0", /* FLASH0_VDD (emmc) */
391e943c43bSUlf Hansson "flash1", /* FLASH1_VDD (sdio1) */
392e943c43bSUlf Hansson "wifi", /* APIO3_VDD (sdio0) */
393e943c43bSUlf Hansson "bb", /* APIO5_VDD */
394e943c43bSUlf Hansson "audio", /* APIO4_VDD */
395e943c43bSUlf Hansson "sdcard", /* SDMMC0_VDD (sdmmc) */
396e943c43bSUlf Hansson "gpio30", /* APIO1_VDD */
397e943c43bSUlf Hansson "gpio1830", /* APIO2_VDD */
398e943c43bSUlf Hansson },
399e943c43bSUlf Hansson .init = rk3288_iodomain_init,
400e943c43bSUlf Hansson };
401e943c43bSUlf Hansson
402*f0d70478SDavid Wu static const struct rockchip_iodomain_soc_data soc_data_rk3308 = {
403*f0d70478SDavid Wu .grf_offset = 0x300,
404*f0d70478SDavid Wu .supply_names = {
405*f0d70478SDavid Wu "vccio0",
406*f0d70478SDavid Wu "vccio1",
407*f0d70478SDavid Wu "vccio2",
408*f0d70478SDavid Wu "vccio3",
409*f0d70478SDavid Wu "vccio4",
410*f0d70478SDavid Wu "vccio5",
411*f0d70478SDavid Wu },
412*f0d70478SDavid Wu .init = rk3308_iodomain_init,
413*f0d70478SDavid Wu };
414*f0d70478SDavid Wu
415e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
416e943c43bSUlf Hansson .grf_offset = 0x410,
417e943c43bSUlf Hansson .supply_names = {
418e943c43bSUlf Hansson "vccio1",
419e943c43bSUlf Hansson "vccio2",
420e943c43bSUlf Hansson "vccio3",
421e943c43bSUlf Hansson "vccio4",
422e943c43bSUlf Hansson "vccio5",
423e943c43bSUlf Hansson "vccio6",
424e943c43bSUlf Hansson "pmuio",
425e943c43bSUlf Hansson },
426e943c43bSUlf Hansson .init = rk3328_iodomain_init,
427e943c43bSUlf Hansson };
428e943c43bSUlf Hansson
429e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
430e943c43bSUlf Hansson .grf_offset = 0x900,
431e943c43bSUlf Hansson .supply_names = {
432e943c43bSUlf Hansson NULL, /* reserved */
433e943c43bSUlf Hansson "dvp", /* DVPIO_VDD */
434e943c43bSUlf Hansson "flash0", /* FLASH0_VDD (emmc) */
435e943c43bSUlf Hansson "wifi", /* APIO2_VDD (sdio0) */
436e943c43bSUlf Hansson NULL,
437e943c43bSUlf Hansson "audio", /* APIO3_VDD */
438e943c43bSUlf Hansson "sdcard", /* SDMMC0_VDD (sdmmc) */
439e943c43bSUlf Hansson "gpio30", /* APIO1_VDD */
440e943c43bSUlf Hansson "gpio1830", /* APIO4_VDD (gpujtag) */
441e943c43bSUlf Hansson },
442e943c43bSUlf Hansson .init = rk3368_iodomain_init,
443e943c43bSUlf Hansson };
444e943c43bSUlf Hansson
445e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
446e943c43bSUlf Hansson .grf_offset = 0x100,
447e943c43bSUlf Hansson .supply_names = {
448e943c43bSUlf Hansson NULL,
449e943c43bSUlf Hansson NULL,
450e943c43bSUlf Hansson NULL,
451e943c43bSUlf Hansson NULL,
452e943c43bSUlf Hansson "pmu", /*PMU IO domain*/
453e943c43bSUlf Hansson "vop", /*LCDC IO domain*/
454e943c43bSUlf Hansson },
455e943c43bSUlf Hansson };
456e943c43bSUlf Hansson
457e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
458e943c43bSUlf Hansson .grf_offset = 0xe640,
459e943c43bSUlf Hansson .supply_names = {
460e943c43bSUlf Hansson "bt656", /* APIO2_VDD */
461e943c43bSUlf Hansson "audio", /* APIO5_VDD */
462e943c43bSUlf Hansson "sdmmc", /* SDMMC0_VDD */
463e943c43bSUlf Hansson "gpio1830", /* APIO4_VDD */
464e943c43bSUlf Hansson },
465e943c43bSUlf Hansson };
466e943c43bSUlf Hansson
467e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
468e943c43bSUlf Hansson .grf_offset = 0x180,
469e943c43bSUlf Hansson .supply_names = {
470e943c43bSUlf Hansson NULL,
471e943c43bSUlf Hansson NULL,
472e943c43bSUlf Hansson NULL,
473e943c43bSUlf Hansson NULL,
474e943c43bSUlf Hansson NULL,
475e943c43bSUlf Hansson NULL,
476e943c43bSUlf Hansson NULL,
477e943c43bSUlf Hansson NULL,
478e943c43bSUlf Hansson NULL,
479e943c43bSUlf Hansson "pmu1830", /* PMUIO2_VDD */
480e943c43bSUlf Hansson },
481e943c43bSUlf Hansson .init = rk3399_pmu_iodomain_init,
482e943c43bSUlf Hansson };
483e943c43bSUlf Hansson
48428b05a64SJianqun Xu static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
48528b05a64SJianqun Xu .grf_offset = 0x140,
48628b05a64SJianqun Xu .supply_names = {
48728b05a64SJianqun Xu "pmuio1",
48828b05a64SJianqun Xu "pmuio2",
48928b05a64SJianqun Xu "vccio1",
49028b05a64SJianqun Xu "vccio2",
49128b05a64SJianqun Xu "vccio3",
49228b05a64SJianqun Xu "vccio4",
49328b05a64SJianqun Xu "vccio5",
49428b05a64SJianqun Xu "vccio6",
49528b05a64SJianqun Xu "vccio7",
49628b05a64SJianqun Xu },
49728b05a64SJianqun Xu .write = rk3568_iodomain_write,
49828b05a64SJianqun Xu };
49928b05a64SJianqun Xu
500e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
501e943c43bSUlf Hansson .grf_offset = 0x404,
502e943c43bSUlf Hansson .supply_names = {
503e943c43bSUlf Hansson NULL,
504e943c43bSUlf Hansson NULL,
505e943c43bSUlf Hansson NULL,
506e943c43bSUlf Hansson NULL,
507e943c43bSUlf Hansson NULL,
508e943c43bSUlf Hansson NULL,
509e943c43bSUlf Hansson NULL,
510e943c43bSUlf Hansson NULL,
511e943c43bSUlf Hansson NULL,
512e943c43bSUlf Hansson NULL,
513e943c43bSUlf Hansson NULL,
514e943c43bSUlf Hansson "vccio1",
515e943c43bSUlf Hansson "vccio2",
516e943c43bSUlf Hansson "vccio3",
517e943c43bSUlf Hansson "vccio5",
518e943c43bSUlf Hansson "vccio6",
519e943c43bSUlf Hansson },
520e943c43bSUlf Hansson
521e943c43bSUlf Hansson };
522e943c43bSUlf Hansson
523e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
524e943c43bSUlf Hansson .grf_offset = 0x104,
525e943c43bSUlf Hansson .supply_names = {
526e943c43bSUlf Hansson "pmu",
527e943c43bSUlf Hansson },
528e943c43bSUlf Hansson };
529e943c43bSUlf Hansson
530570ed4e5SJianqun Xu static const struct rockchip_iodomain_soc_data soc_data_rv1126_pmu = {
531570ed4e5SJianqun Xu .grf_offset = 0x140,
532570ed4e5SJianqun Xu .supply_names = {
533570ed4e5SJianqun Xu NULL,
534570ed4e5SJianqun Xu "vccio1",
535570ed4e5SJianqun Xu "vccio2",
536570ed4e5SJianqun Xu "vccio3",
537570ed4e5SJianqun Xu "vccio4",
538570ed4e5SJianqun Xu "vccio5",
539570ed4e5SJianqun Xu "vccio6",
540570ed4e5SJianqun Xu "vccio7",
541570ed4e5SJianqun Xu "pmuio0",
542570ed4e5SJianqun Xu "pmuio1",
543570ed4e5SJianqun Xu },
544570ed4e5SJianqun Xu };
545570ed4e5SJianqun Xu
546e943c43bSUlf Hansson static const struct of_device_id rockchip_iodomain_match[] = {
547e943c43bSUlf Hansson {
548e943c43bSUlf Hansson .compatible = "rockchip,px30-io-voltage-domain",
549e943c43bSUlf Hansson .data = (void *)&soc_data_px30
550e943c43bSUlf Hansson },
551e943c43bSUlf Hansson {
552e943c43bSUlf Hansson .compatible = "rockchip,px30-pmu-io-voltage-domain",
553e943c43bSUlf Hansson .data = (void *)&soc_data_px30_pmu
554e943c43bSUlf Hansson },
555e943c43bSUlf Hansson {
556e943c43bSUlf Hansson .compatible = "rockchip,rk3188-io-voltage-domain",
557e943c43bSUlf Hansson .data = &soc_data_rk3188
558e943c43bSUlf Hansson },
559e943c43bSUlf Hansson {
560e943c43bSUlf Hansson .compatible = "rockchip,rk3228-io-voltage-domain",
561e943c43bSUlf Hansson .data = &soc_data_rk3228
562e943c43bSUlf Hansson },
563e943c43bSUlf Hansson {
564e943c43bSUlf Hansson .compatible = "rockchip,rk3288-io-voltage-domain",
565e943c43bSUlf Hansson .data = &soc_data_rk3288
566e943c43bSUlf Hansson },
567e943c43bSUlf Hansson {
568*f0d70478SDavid Wu .compatible = "rockchip,rk3308-io-voltage-domain",
569*f0d70478SDavid Wu .data = &soc_data_rk3308
570*f0d70478SDavid Wu },
571*f0d70478SDavid Wu {
572e943c43bSUlf Hansson .compatible = "rockchip,rk3328-io-voltage-domain",
573e943c43bSUlf Hansson .data = &soc_data_rk3328
574e943c43bSUlf Hansson },
575e943c43bSUlf Hansson {
576e943c43bSUlf Hansson .compatible = "rockchip,rk3368-io-voltage-domain",
577e943c43bSUlf Hansson .data = &soc_data_rk3368
578e943c43bSUlf Hansson },
579e943c43bSUlf Hansson {
580e943c43bSUlf Hansson .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
581e943c43bSUlf Hansson .data = &soc_data_rk3368_pmu
582e943c43bSUlf Hansson },
583e943c43bSUlf Hansson {
584e943c43bSUlf Hansson .compatible = "rockchip,rk3399-io-voltage-domain",
585e943c43bSUlf Hansson .data = &soc_data_rk3399
586e943c43bSUlf Hansson },
587e943c43bSUlf Hansson {
588e943c43bSUlf Hansson .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
589e943c43bSUlf Hansson .data = &soc_data_rk3399_pmu
590e943c43bSUlf Hansson },
591e943c43bSUlf Hansson {
59228b05a64SJianqun Xu .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
59328b05a64SJianqun Xu .data = &soc_data_rk3568_pmu
59428b05a64SJianqun Xu },
59528b05a64SJianqun Xu {
596e943c43bSUlf Hansson .compatible = "rockchip,rv1108-io-voltage-domain",
597e943c43bSUlf Hansson .data = &soc_data_rv1108
598e943c43bSUlf Hansson },
599e943c43bSUlf Hansson {
600e943c43bSUlf Hansson .compatible = "rockchip,rv1108-pmu-io-voltage-domain",
601e943c43bSUlf Hansson .data = &soc_data_rv1108_pmu
602e943c43bSUlf Hansson },
603570ed4e5SJianqun Xu {
604570ed4e5SJianqun Xu .compatible = "rockchip,rv1126-pmu-io-voltage-domain",
605570ed4e5SJianqun Xu .data = &soc_data_rv1126_pmu
606570ed4e5SJianqun Xu },
607e943c43bSUlf Hansson { /* sentinel */ },
608e943c43bSUlf Hansson };
609e943c43bSUlf Hansson MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
610e943c43bSUlf Hansson
rockchip_iodomain_probe(struct platform_device * pdev)611e943c43bSUlf Hansson static int rockchip_iodomain_probe(struct platform_device *pdev)
612e943c43bSUlf Hansson {
613e943c43bSUlf Hansson struct device_node *np = pdev->dev.of_node;
614e943c43bSUlf Hansson const struct of_device_id *match;
615e943c43bSUlf Hansson struct rockchip_iodomain *iod;
616e943c43bSUlf Hansson struct device *parent;
617e943c43bSUlf Hansson int i, ret = 0;
618e943c43bSUlf Hansson
619e943c43bSUlf Hansson if (!np)
620e943c43bSUlf Hansson return -ENODEV;
621e943c43bSUlf Hansson
622e943c43bSUlf Hansson iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
623e943c43bSUlf Hansson if (!iod)
624e943c43bSUlf Hansson return -ENOMEM;
625e943c43bSUlf Hansson
626e943c43bSUlf Hansson iod->dev = &pdev->dev;
627e943c43bSUlf Hansson platform_set_drvdata(pdev, iod);
628e943c43bSUlf Hansson
629e943c43bSUlf Hansson match = of_match_node(rockchip_iodomain_match, np);
630e943c43bSUlf Hansson iod->soc_data = match->data;
631e943c43bSUlf Hansson
63228b05a64SJianqun Xu if (iod->soc_data->write)
63328b05a64SJianqun Xu iod->write = iod->soc_data->write;
63428b05a64SJianqun Xu else
63528b05a64SJianqun Xu iod->write = rockchip_iodomain_write;
63628b05a64SJianqun Xu
637e943c43bSUlf Hansson parent = pdev->dev.parent;
638e943c43bSUlf Hansson if (parent && parent->of_node) {
639e943c43bSUlf Hansson iod->grf = syscon_node_to_regmap(parent->of_node);
640e943c43bSUlf Hansson } else {
641e943c43bSUlf Hansson dev_dbg(&pdev->dev, "falling back to old binding\n");
642e943c43bSUlf Hansson iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
643e943c43bSUlf Hansson }
644e943c43bSUlf Hansson
645e943c43bSUlf Hansson if (IS_ERR(iod->grf)) {
646e943c43bSUlf Hansson dev_err(&pdev->dev, "couldn't find grf regmap\n");
647e943c43bSUlf Hansson return PTR_ERR(iod->grf);
648e943c43bSUlf Hansson }
649e943c43bSUlf Hansson
650e943c43bSUlf Hansson for (i = 0; i < MAX_SUPPLIES; i++) {
651e943c43bSUlf Hansson const char *supply_name = iod->soc_data->supply_names[i];
652e943c43bSUlf Hansson struct rockchip_iodomain_supply *supply = &iod->supplies[i];
653e943c43bSUlf Hansson struct regulator *reg;
654e943c43bSUlf Hansson int uV;
655e943c43bSUlf Hansson
656e943c43bSUlf Hansson if (!supply_name)
657e943c43bSUlf Hansson continue;
658e943c43bSUlf Hansson
659e943c43bSUlf Hansson reg = devm_regulator_get_optional(iod->dev, supply_name);
660e943c43bSUlf Hansson if (IS_ERR(reg)) {
661e943c43bSUlf Hansson ret = PTR_ERR(reg);
662e943c43bSUlf Hansson
663e943c43bSUlf Hansson /* If a supply wasn't specified, that's OK */
664e943c43bSUlf Hansson if (ret == -ENODEV)
665e943c43bSUlf Hansson continue;
666e943c43bSUlf Hansson else if (ret != -EPROBE_DEFER)
667e943c43bSUlf Hansson dev_err(iod->dev, "couldn't get regulator %s\n",
668e943c43bSUlf Hansson supply_name);
669e943c43bSUlf Hansson goto unreg_notify;
670e943c43bSUlf Hansson }
671e943c43bSUlf Hansson
672e943c43bSUlf Hansson /* set initial correct value */
673e943c43bSUlf Hansson uV = regulator_get_voltage(reg);
674e943c43bSUlf Hansson
675e943c43bSUlf Hansson /* must be a regulator we can get the voltage of */
676e943c43bSUlf Hansson if (uV < 0) {
677e943c43bSUlf Hansson dev_err(iod->dev, "Can't determine voltage: %s\n",
678e943c43bSUlf Hansson supply_name);
679c2867b2eSZhang Changzhong ret = uV;
680e943c43bSUlf Hansson goto unreg_notify;
681e943c43bSUlf Hansson }
682e943c43bSUlf Hansson
683e943c43bSUlf Hansson if (uV > MAX_VOLTAGE_3_3) {
684e943c43bSUlf Hansson dev_crit(iod->dev,
685e943c43bSUlf Hansson "%d uV is too high. May damage SoC!\n",
686e943c43bSUlf Hansson uV);
687e943c43bSUlf Hansson ret = -EINVAL;
688e943c43bSUlf Hansson goto unreg_notify;
689e943c43bSUlf Hansson }
690e943c43bSUlf Hansson
691e943c43bSUlf Hansson /* setup our supply */
692e943c43bSUlf Hansson supply->idx = i;
693e943c43bSUlf Hansson supply->iod = iod;
694e943c43bSUlf Hansson supply->reg = reg;
695e943c43bSUlf Hansson supply->nb.notifier_call = rockchip_iodomain_notify;
696e943c43bSUlf Hansson
69728b05a64SJianqun Xu ret = iod->write(supply, uV);
698e943c43bSUlf Hansson if (ret) {
699e943c43bSUlf Hansson supply->reg = NULL;
700e943c43bSUlf Hansson goto unreg_notify;
701e943c43bSUlf Hansson }
702e943c43bSUlf Hansson
703e943c43bSUlf Hansson /* register regulator notifier */
704e943c43bSUlf Hansson ret = regulator_register_notifier(reg, &supply->nb);
705e943c43bSUlf Hansson if (ret) {
706e943c43bSUlf Hansson dev_err(&pdev->dev,
707e943c43bSUlf Hansson "regulator notifier request failed\n");
708e943c43bSUlf Hansson supply->reg = NULL;
709e943c43bSUlf Hansson goto unreg_notify;
710e943c43bSUlf Hansson }
711e943c43bSUlf Hansson }
712e943c43bSUlf Hansson
713e943c43bSUlf Hansson if (iod->soc_data->init)
714e943c43bSUlf Hansson iod->soc_data->init(iod);
715e943c43bSUlf Hansson
716e943c43bSUlf Hansson return 0;
717e943c43bSUlf Hansson
718e943c43bSUlf Hansson unreg_notify:
719e943c43bSUlf Hansson for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
720e943c43bSUlf Hansson struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
721e943c43bSUlf Hansson
722e943c43bSUlf Hansson if (io_supply->reg)
723e943c43bSUlf Hansson regulator_unregister_notifier(io_supply->reg,
724e943c43bSUlf Hansson &io_supply->nb);
725e943c43bSUlf Hansson }
726e943c43bSUlf Hansson
727e943c43bSUlf Hansson return ret;
728e943c43bSUlf Hansson }
729e943c43bSUlf Hansson
rockchip_iodomain_remove(struct platform_device * pdev)73020bd1191SUwe Kleine-König static void rockchip_iodomain_remove(struct platform_device *pdev)
731e943c43bSUlf Hansson {
732e943c43bSUlf Hansson struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
733e943c43bSUlf Hansson int i;
734e943c43bSUlf Hansson
735e943c43bSUlf Hansson for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
736e943c43bSUlf Hansson struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
737e943c43bSUlf Hansson
738e943c43bSUlf Hansson if (io_supply->reg)
739e943c43bSUlf Hansson regulator_unregister_notifier(io_supply->reg,
740e943c43bSUlf Hansson &io_supply->nb);
741e943c43bSUlf Hansson }
742e943c43bSUlf Hansson }
743e943c43bSUlf Hansson
744e943c43bSUlf Hansson static struct platform_driver rockchip_iodomain_driver = {
745e943c43bSUlf Hansson .probe = rockchip_iodomain_probe,
74620bd1191SUwe Kleine-König .remove_new = rockchip_iodomain_remove,
747e943c43bSUlf Hansson .driver = {
748e943c43bSUlf Hansson .name = "rockchip-iodomain",
749e943c43bSUlf Hansson .of_match_table = rockchip_iodomain_match,
750e943c43bSUlf Hansson },
751e943c43bSUlf Hansson };
752e943c43bSUlf Hansson
753e943c43bSUlf Hansson module_platform_driver(rockchip_iodomain_driver);
754e943c43bSUlf Hansson
755e943c43bSUlf Hansson MODULE_DESCRIPTION("Rockchip IO-domain driver");
756e943c43bSUlf Hansson MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
757e943c43bSUlf Hansson MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
758e943c43bSUlf Hansson MODULE_LICENSE("GPL v2");
759