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