xref: /rk3399_rockchip-uboot/drivers/gpio/pm8916_gpio.c (revision 04048d58a8fdc607010cb611d0656c4f6cae6296)
1120800dfSMateusz Kulikowski /*
2120800dfSMateusz Kulikowski  * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
3120800dfSMateusz Kulikowski  *
4120800dfSMateusz Kulikowski  * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
5120800dfSMateusz Kulikowski  *
6120800dfSMateusz Kulikowski  * SPDX-License-Identifier:	GPL-2.0+
7120800dfSMateusz Kulikowski  */
8120800dfSMateusz Kulikowski 
9120800dfSMateusz Kulikowski #include <common.h>
10120800dfSMateusz Kulikowski #include <dm.h>
11120800dfSMateusz Kulikowski #include <power/pmic.h>
12120800dfSMateusz Kulikowski #include <spmi/spmi.h>
13120800dfSMateusz Kulikowski #include <asm/io.h>
14120800dfSMateusz Kulikowski #include <asm/gpio.h>
15120800dfSMateusz Kulikowski #include <linux/bitops.h>
16120800dfSMateusz Kulikowski 
17120800dfSMateusz Kulikowski DECLARE_GLOBAL_DATA_PTR;
18120800dfSMateusz Kulikowski 
19120800dfSMateusz Kulikowski /* Register offset for each gpio */
20120800dfSMateusz Kulikowski #define REG_OFFSET(x)          ((x) * 0x100)
21120800dfSMateusz Kulikowski 
22120800dfSMateusz Kulikowski /* Register maps */
23120800dfSMateusz Kulikowski 
24120800dfSMateusz Kulikowski /* Type and subtype are shared for all pm8916 peripherals */
25120800dfSMateusz Kulikowski #define REG_TYPE               0x4
26120800dfSMateusz Kulikowski #define REG_SUBTYPE            0x5
27120800dfSMateusz Kulikowski 
28120800dfSMateusz Kulikowski #define REG_STATUS             0x08
29120800dfSMateusz Kulikowski #define REG_STATUS_VAL_MASK    0x1
30120800dfSMateusz Kulikowski 
31120800dfSMateusz Kulikowski /* MODE_CTL */
32120800dfSMateusz Kulikowski #define REG_CTL           0x40
33120800dfSMateusz Kulikowski #define REG_CTL_MODE_MASK       0x70
34120800dfSMateusz Kulikowski #define REG_CTL_MODE_INPUT      0x00
35120800dfSMateusz Kulikowski #define REG_CTL_MODE_INOUT      0x20
36120800dfSMateusz Kulikowski #define REG_CTL_MODE_OUTPUT     0x10
37120800dfSMateusz Kulikowski #define REG_CTL_OUTPUT_MASK     0x0F
38120800dfSMateusz Kulikowski 
39120800dfSMateusz Kulikowski #define REG_DIG_VIN_CTL        0x41
40120800dfSMateusz Kulikowski #define REG_DIG_VIN_VIN0       0
41120800dfSMateusz Kulikowski 
42120800dfSMateusz Kulikowski #define REG_DIG_PULL_CTL       0x42
43120800dfSMateusz Kulikowski #define REG_DIG_PULL_NO_PU     0x5
44120800dfSMateusz Kulikowski 
45120800dfSMateusz Kulikowski #define REG_DIG_OUT_CTL        0x45
46120800dfSMateusz Kulikowski #define REG_DIG_OUT_CTL_CMOS   (0x0 << 4)
47120800dfSMateusz Kulikowski #define REG_DIG_OUT_CTL_DRIVE_L 0x1
48120800dfSMateusz Kulikowski 
49120800dfSMateusz Kulikowski #define REG_EN_CTL             0x46
50120800dfSMateusz Kulikowski #define REG_EN_CTL_ENABLE      (1 << 7)
51120800dfSMateusz Kulikowski 
52120800dfSMateusz Kulikowski struct pm8916_gpio_bank {
53aa997d1dSTom Rini 	uint32_t pid; /* Peripheral ID on SPMI bus */
54120800dfSMateusz Kulikowski };
55120800dfSMateusz Kulikowski 
pm8916_gpio_set_direction(struct udevice * dev,unsigned offset,bool input,int value)56120800dfSMateusz Kulikowski static int pm8916_gpio_set_direction(struct udevice *dev, unsigned offset,
57120800dfSMateusz Kulikowski 				     bool input, int value)
58120800dfSMateusz Kulikowski {
59120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
60120800dfSMateusz Kulikowski 	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
61120800dfSMateusz Kulikowski 	int ret;
62120800dfSMateusz Kulikowski 
63120800dfSMateusz Kulikowski 	/* Disable the GPIO */
64120800dfSMateusz Kulikowski 	ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
65120800dfSMateusz Kulikowski 			      REG_EN_CTL_ENABLE, 0);
66120800dfSMateusz Kulikowski 	if (ret < 0)
67120800dfSMateusz Kulikowski 		return ret;
68120800dfSMateusz Kulikowski 
69120800dfSMateusz Kulikowski 	/* Select the mode */
70120800dfSMateusz Kulikowski 	if (input)
71120800dfSMateusz Kulikowski 		ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
72120800dfSMateusz Kulikowski 				     REG_CTL_MODE_INPUT);
73120800dfSMateusz Kulikowski 	else
74120800dfSMateusz Kulikowski 		ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
75120800dfSMateusz Kulikowski 				     REG_CTL_MODE_INOUT | (value ? 1 : 0));
76120800dfSMateusz Kulikowski 	if (ret < 0)
77120800dfSMateusz Kulikowski 		return ret;
78120800dfSMateusz Kulikowski 
79120800dfSMateusz Kulikowski 	/* Set the right pull (no pull) */
80120800dfSMateusz Kulikowski 	ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
81120800dfSMateusz Kulikowski 			     REG_DIG_PULL_NO_PU);
82120800dfSMateusz Kulikowski 	if (ret < 0)
83120800dfSMateusz Kulikowski 		return ret;
84120800dfSMateusz Kulikowski 
85120800dfSMateusz Kulikowski 	/* Configure output pin drivers if needed */
86120800dfSMateusz Kulikowski 	if (!input) {
87120800dfSMateusz Kulikowski 		/* Select the VIN - VIN0, pin is input so it doesn't matter */
88120800dfSMateusz Kulikowski 		ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
89120800dfSMateusz Kulikowski 				     REG_DIG_VIN_VIN0);
90120800dfSMateusz Kulikowski 		if (ret < 0)
91120800dfSMateusz Kulikowski 			return ret;
92120800dfSMateusz Kulikowski 
93120800dfSMateusz Kulikowski 		/* Set the right dig out control */
94120800dfSMateusz Kulikowski 		ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
95120800dfSMateusz Kulikowski 				     REG_DIG_OUT_CTL_CMOS |
96120800dfSMateusz Kulikowski 				     REG_DIG_OUT_CTL_DRIVE_L);
97120800dfSMateusz Kulikowski 		if (ret < 0)
98120800dfSMateusz Kulikowski 			return ret;
99120800dfSMateusz Kulikowski 	}
100120800dfSMateusz Kulikowski 
101120800dfSMateusz Kulikowski 	/* Enable the GPIO */
102120800dfSMateusz Kulikowski 	return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
103120800dfSMateusz Kulikowski 			       REG_EN_CTL_ENABLE);
104120800dfSMateusz Kulikowski }
105120800dfSMateusz Kulikowski 
pm8916_gpio_direction_input(struct udevice * dev,unsigned offset)106120800dfSMateusz Kulikowski static int pm8916_gpio_direction_input(struct udevice *dev, unsigned offset)
107120800dfSMateusz Kulikowski {
108120800dfSMateusz Kulikowski 	return pm8916_gpio_set_direction(dev, offset, true, 0);
109120800dfSMateusz Kulikowski }
110120800dfSMateusz Kulikowski 
pm8916_gpio_direction_output(struct udevice * dev,unsigned offset,int value)111120800dfSMateusz Kulikowski static int pm8916_gpio_direction_output(struct udevice *dev, unsigned offset,
112120800dfSMateusz Kulikowski 					int value)
113120800dfSMateusz Kulikowski {
114120800dfSMateusz Kulikowski 	return pm8916_gpio_set_direction(dev, offset, false, value);
115120800dfSMateusz Kulikowski }
116120800dfSMateusz Kulikowski 
pm8916_gpio_get_function(struct udevice * dev,unsigned offset)117120800dfSMateusz Kulikowski static int pm8916_gpio_get_function(struct udevice *dev, unsigned offset)
118120800dfSMateusz Kulikowski {
119120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
120120800dfSMateusz Kulikowski 	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
121120800dfSMateusz Kulikowski 	int reg;
122120800dfSMateusz Kulikowski 
123120800dfSMateusz Kulikowski 	/* Set the output value of the gpio */
124120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
125120800dfSMateusz Kulikowski 	if (reg < 0)
126120800dfSMateusz Kulikowski 		return reg;
127120800dfSMateusz Kulikowski 
128120800dfSMateusz Kulikowski 	switch (reg & REG_CTL_MODE_MASK) {
129120800dfSMateusz Kulikowski 	case REG_CTL_MODE_INPUT:
130120800dfSMateusz Kulikowski 		return GPIOF_INPUT;
131120800dfSMateusz Kulikowski 	case REG_CTL_MODE_INOUT: /* Fallthrough */
132120800dfSMateusz Kulikowski 	case REG_CTL_MODE_OUTPUT:
133120800dfSMateusz Kulikowski 		return GPIOF_OUTPUT;
134120800dfSMateusz Kulikowski 	default:
135120800dfSMateusz Kulikowski 		return GPIOF_UNKNOWN;
136120800dfSMateusz Kulikowski 	}
137120800dfSMateusz Kulikowski }
138120800dfSMateusz Kulikowski 
pm8916_gpio_get_value(struct udevice * dev,unsigned offset)139120800dfSMateusz Kulikowski static int pm8916_gpio_get_value(struct udevice *dev, unsigned offset)
140120800dfSMateusz Kulikowski {
141120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
142120800dfSMateusz Kulikowski 	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
143120800dfSMateusz Kulikowski 	int reg;
144120800dfSMateusz Kulikowski 
145120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
146120800dfSMateusz Kulikowski 	if (reg < 0)
147120800dfSMateusz Kulikowski 		return reg;
148120800dfSMateusz Kulikowski 
149120800dfSMateusz Kulikowski 	return !!(reg & REG_STATUS_VAL_MASK);
150120800dfSMateusz Kulikowski }
151120800dfSMateusz Kulikowski 
pm8916_gpio_set_value(struct udevice * dev,unsigned offset,int value)152120800dfSMateusz Kulikowski static int pm8916_gpio_set_value(struct udevice *dev, unsigned offset,
153120800dfSMateusz Kulikowski 				 int value)
154120800dfSMateusz Kulikowski {
155120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
156120800dfSMateusz Kulikowski 	uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
157120800dfSMateusz Kulikowski 
158120800dfSMateusz Kulikowski 	/* Set the output value of the gpio */
159120800dfSMateusz Kulikowski 	return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
160120800dfSMateusz Kulikowski 			       REG_CTL_OUTPUT_MASK, !!value);
161120800dfSMateusz Kulikowski }
162120800dfSMateusz Kulikowski 
163120800dfSMateusz Kulikowski static const struct dm_gpio_ops pm8916_gpio_ops = {
164120800dfSMateusz Kulikowski 	.direction_input	= pm8916_gpio_direction_input,
165120800dfSMateusz Kulikowski 	.direction_output	= pm8916_gpio_direction_output,
166120800dfSMateusz Kulikowski 	.get_value		= pm8916_gpio_get_value,
167120800dfSMateusz Kulikowski 	.set_value		= pm8916_gpio_set_value,
168120800dfSMateusz Kulikowski 	.get_function		= pm8916_gpio_get_function,
169120800dfSMateusz Kulikowski };
170120800dfSMateusz Kulikowski 
pm8916_gpio_probe(struct udevice * dev)171120800dfSMateusz Kulikowski static int pm8916_gpio_probe(struct udevice *dev)
172120800dfSMateusz Kulikowski {
173120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
174120800dfSMateusz Kulikowski 	int reg;
175120800dfSMateusz Kulikowski 
176*04048d58SSimon Glass 	priv->pid = dev_read_addr(dev);
177120800dfSMateusz Kulikowski 	if (priv->pid == FDT_ADDR_T_NONE)
178120800dfSMateusz Kulikowski 		return -EINVAL;
179120800dfSMateusz Kulikowski 
180120800dfSMateusz Kulikowski 	/* Do a sanity check */
181120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
182120800dfSMateusz Kulikowski 	if (reg != 0x10)
183120800dfSMateusz Kulikowski 		return -ENODEV;
184120800dfSMateusz Kulikowski 
185120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
186120800dfSMateusz Kulikowski 	if (reg != 0x5)
187120800dfSMateusz Kulikowski 		return -ENODEV;
188120800dfSMateusz Kulikowski 
189120800dfSMateusz Kulikowski 	return 0;
190120800dfSMateusz Kulikowski }
191120800dfSMateusz Kulikowski 
pm8916_gpio_ofdata_to_platdata(struct udevice * dev)192120800dfSMateusz Kulikowski static int pm8916_gpio_ofdata_to_platdata(struct udevice *dev)
193120800dfSMateusz Kulikowski {
194120800dfSMateusz Kulikowski 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
195120800dfSMateusz Kulikowski 
196*04048d58SSimon Glass 	uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
197*04048d58SSimon Glass 	uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
198120800dfSMateusz Kulikowski 	if (uc_priv->bank_name == NULL)
199120800dfSMateusz Kulikowski 		uc_priv->bank_name = "pm8916";
200120800dfSMateusz Kulikowski 
201120800dfSMateusz Kulikowski 	return 0;
202120800dfSMateusz Kulikowski }
203120800dfSMateusz Kulikowski 
204120800dfSMateusz Kulikowski static const struct udevice_id pm8916_gpio_ids[] = {
205120800dfSMateusz Kulikowski 	{ .compatible = "qcom,pm8916-gpio" },
206120800dfSMateusz Kulikowski 	{ }
207120800dfSMateusz Kulikowski };
208120800dfSMateusz Kulikowski 
209120800dfSMateusz Kulikowski U_BOOT_DRIVER(gpio_pm8916) = {
210120800dfSMateusz Kulikowski 	.name	= "gpio_pm8916",
211120800dfSMateusz Kulikowski 	.id	= UCLASS_GPIO,
212120800dfSMateusz Kulikowski 	.of_match = pm8916_gpio_ids,
213120800dfSMateusz Kulikowski 	.ofdata_to_platdata = pm8916_gpio_ofdata_to_platdata,
214120800dfSMateusz Kulikowski 	.probe	= pm8916_gpio_probe,
215120800dfSMateusz Kulikowski 	.ops	= &pm8916_gpio_ops,
216120800dfSMateusz Kulikowski 	.priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank),
217120800dfSMateusz Kulikowski };
218120800dfSMateusz Kulikowski 
219120800dfSMateusz Kulikowski 
220120800dfSMateusz Kulikowski /* Add pmic buttons as GPIO as well - there is no generic way for now */
221120800dfSMateusz Kulikowski #define PON_INT_RT_STS                        0x10
222120800dfSMateusz Kulikowski #define KPDPWR_ON_INT_BIT                     0
223120800dfSMateusz Kulikowski #define RESIN_ON_INT_BIT                      1
224120800dfSMateusz Kulikowski 
pm8941_pwrkey_get_function(struct udevice * dev,unsigned offset)225120800dfSMateusz Kulikowski static int pm8941_pwrkey_get_function(struct udevice *dev, unsigned offset)
226120800dfSMateusz Kulikowski {
227120800dfSMateusz Kulikowski 	return GPIOF_INPUT;
228120800dfSMateusz Kulikowski }
229120800dfSMateusz Kulikowski 
pm8941_pwrkey_get_value(struct udevice * dev,unsigned offset)230120800dfSMateusz Kulikowski static int pm8941_pwrkey_get_value(struct udevice *dev, unsigned offset)
231120800dfSMateusz Kulikowski {
232120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
233120800dfSMateusz Kulikowski 
234120800dfSMateusz Kulikowski 	int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
235120800dfSMateusz Kulikowski 
236120800dfSMateusz Kulikowski 	if (reg < 0)
237120800dfSMateusz Kulikowski 		return 0;
238120800dfSMateusz Kulikowski 
239120800dfSMateusz Kulikowski 	switch (offset) {
240120800dfSMateusz Kulikowski 	case 0: /* Power button */
241120800dfSMateusz Kulikowski 		return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
242120800dfSMateusz Kulikowski 		break;
243120800dfSMateusz Kulikowski 	case 1: /* Reset button */
244120800dfSMateusz Kulikowski 	default:
245120800dfSMateusz Kulikowski 		return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
246120800dfSMateusz Kulikowski 		break;
247120800dfSMateusz Kulikowski 	}
248120800dfSMateusz Kulikowski }
249120800dfSMateusz Kulikowski 
250120800dfSMateusz Kulikowski static const struct dm_gpio_ops pm8941_pwrkey_ops = {
251120800dfSMateusz Kulikowski 	.get_value		= pm8941_pwrkey_get_value,
252120800dfSMateusz Kulikowski 	.get_function		= pm8941_pwrkey_get_function,
253120800dfSMateusz Kulikowski };
254120800dfSMateusz Kulikowski 
pm8941_pwrkey_probe(struct udevice * dev)255120800dfSMateusz Kulikowski static int pm8941_pwrkey_probe(struct udevice *dev)
256120800dfSMateusz Kulikowski {
257120800dfSMateusz Kulikowski 	struct pm8916_gpio_bank *priv = dev_get_priv(dev);
258120800dfSMateusz Kulikowski 	int reg;
259120800dfSMateusz Kulikowski 
260a821c4afSSimon Glass 	priv->pid = devfdt_get_addr(dev);
261120800dfSMateusz Kulikowski 	if (priv->pid == FDT_ADDR_T_NONE)
262120800dfSMateusz Kulikowski 		return -EINVAL;
263120800dfSMateusz Kulikowski 
264120800dfSMateusz Kulikowski 	/* Do a sanity check */
265120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
266120800dfSMateusz Kulikowski 	if (reg != 0x1)
267120800dfSMateusz Kulikowski 		return -ENODEV;
268120800dfSMateusz Kulikowski 
269120800dfSMateusz Kulikowski 	reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
270120800dfSMateusz Kulikowski 	if (reg != 0x1)
271120800dfSMateusz Kulikowski 		return -ENODEV;
272120800dfSMateusz Kulikowski 
273120800dfSMateusz Kulikowski 	return 0;
274120800dfSMateusz Kulikowski }
275120800dfSMateusz Kulikowski 
pm8941_pwrkey_ofdata_to_platdata(struct udevice * dev)276120800dfSMateusz Kulikowski static int pm8941_pwrkey_ofdata_to_platdata(struct udevice *dev)
277120800dfSMateusz Kulikowski {
278120800dfSMateusz Kulikowski 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
279120800dfSMateusz Kulikowski 
280120800dfSMateusz Kulikowski 	uc_priv->gpio_count = 2;
281120800dfSMateusz Kulikowski 	if (uc_priv->bank_name == NULL)
282120800dfSMateusz Kulikowski 		uc_priv->bank_name = "pm8916_key";
283120800dfSMateusz Kulikowski 
284120800dfSMateusz Kulikowski 	return 0;
285120800dfSMateusz Kulikowski }
286120800dfSMateusz Kulikowski 
287120800dfSMateusz Kulikowski static const struct udevice_id pm8941_pwrkey_ids[] = {
288120800dfSMateusz Kulikowski 	{ .compatible = "qcom,pm8916-pwrkey" },
289120800dfSMateusz Kulikowski 	{ }
290120800dfSMateusz Kulikowski };
291120800dfSMateusz Kulikowski 
292120800dfSMateusz Kulikowski U_BOOT_DRIVER(pwrkey_pm8941) = {
293120800dfSMateusz Kulikowski 	.name	= "pwrkey_pm8916",
294120800dfSMateusz Kulikowski 	.id	= UCLASS_GPIO,
295120800dfSMateusz Kulikowski 	.of_match = pm8941_pwrkey_ids,
296120800dfSMateusz Kulikowski 	.ofdata_to_platdata = pm8941_pwrkey_ofdata_to_platdata,
297120800dfSMateusz Kulikowski 	.probe	= pm8941_pwrkey_probe,
298120800dfSMateusz Kulikowski 	.ops	= &pm8941_pwrkey_ops,
299120800dfSMateusz Kulikowski 	.priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank),
300120800dfSMateusz Kulikowski };
301