1 // SPDX-License-Identifier: GPL-2.0+
3 * Qualcomm generic pmic gpio driver
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
11 #include <power/pmic.h>
12 #include <spmi/spmi.h>
15 #include <linux/bitops.h>
17 /* Register offset for each gpio */
18 #define REG_OFFSET(x) ((x) * 0x100)
22 /* Type and subtype are shared for all PMIC peripherals */
24 #define REG_SUBTYPE 0x5
26 /* GPIO peripheral type and subtype out_values */
27 #define REG_TYPE_VAL 0x10
28 #define REG_SUBTYPE_GPIO_4CH 0x1
29 #define REG_SUBTYPE_GPIOC_4CH 0x5
30 #define REG_SUBTYPE_GPIO_8CH 0x9
31 #define REG_SUBTYPE_GPIOC_8CH 0xd
32 #define REG_SUBTYPE_GPIO_LV 0x10
33 #define REG_SUBTYPE_GPIO_MV 0x11
35 #define REG_STATUS 0x08
36 #define REG_STATUS_VAL_MASK 0x1
40 #define REG_CTL_MODE_MASK 0x70
41 #define REG_CTL_MODE_INPUT 0x00
42 #define REG_CTL_MODE_INOUT 0x20
43 #define REG_CTL_MODE_OUTPUT 0x10
44 #define REG_CTL_OUTPUT_MASK 0x0F
45 #define REG_CTL_LV_MV_MODE_MASK 0x3
46 #define REG_CTL_LV_MV_MODE_INPUT 0x0
47 #define REG_CTL_LV_MV_MODE_INOUT 0x2
48 #define REG_CTL_LV_MV_MODE_OUTPUT 0x1
50 #define REG_DIG_VIN_CTL 0x41
51 #define REG_DIG_VIN_VIN0 0
53 #define REG_DIG_PULL_CTL 0x42
54 #define REG_DIG_PULL_NO_PU 0x5
56 #define REG_LV_MV_OUTPUT_CTL 0x44
57 #define REG_LV_MV_OUTPUT_CTL_MASK 0x80
58 #define REG_LV_MV_OUTPUT_CTL_SHIFT 7
60 #define REG_DIG_OUT_CTL 0x45
61 #define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
62 #define REG_DIG_OUT_CTL_DRIVE_L 0x1
64 #define REG_EN_CTL 0x46
65 #define REG_EN_CTL_ENABLE (1 << 7)
67 struct qcom_gpio_bank {
68 uint32_t pid; /* Peripheral ID on SPMI bus */
69 bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
72 static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
73 bool input, int value)
75 struct qcom_gpio_bank *priv = dev_get_priv(dev);
76 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
80 /* Disable the GPIO */
81 ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
82 REG_EN_CTL_ENABLE, 0);
86 /* Select the mode and output */
87 if (priv->lv_mv_type) {
89 reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
91 reg_ctl_val = REG_CTL_LV_MV_MODE_INOUT;
94 reg_ctl_val = REG_CTL_MODE_INPUT;
96 reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
99 ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val);
103 if (priv->lv_mv_type && !input) {
104 ret = pmic_reg_write(dev->parent,
105 gpio_base + REG_LV_MV_OUTPUT_CTL,
106 !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
111 /* Set the right pull (no pull) */
112 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
117 /* Configure output pin drivers if needed */
119 /* Select the VIN - VIN0, pin is input so it doesn't matter */
120 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
125 /* Set the right dig out control */
126 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
127 REG_DIG_OUT_CTL_CMOS |
128 REG_DIG_OUT_CTL_DRIVE_L);
133 /* Enable the GPIO */
134 return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
138 static int qcom_gpio_direction_input(struct udevice *dev, unsigned offset)
140 return qcom_gpio_set_direction(dev, offset, true, 0);
143 static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset,
146 return qcom_gpio_set_direction(dev, offset, false, value);
149 static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
151 struct qcom_gpio_bank *priv = dev_get_priv(dev);
152 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
155 reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
159 if (priv->lv_mv_type) {
160 switch (reg & REG_CTL_LV_MV_MODE_MASK) {
161 case REG_CTL_LV_MV_MODE_INPUT:
163 case REG_CTL_LV_MV_MODE_INOUT: /* Fallthrough */
164 case REG_CTL_LV_MV_MODE_OUTPUT:
167 return GPIOF_UNKNOWN;
170 switch (reg & REG_CTL_MODE_MASK) {
171 case REG_CTL_MODE_INPUT:
173 case REG_CTL_MODE_INOUT: /* Fallthrough */
174 case REG_CTL_MODE_OUTPUT:
177 return GPIOF_UNKNOWN;
182 static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
184 struct qcom_gpio_bank *priv = dev_get_priv(dev);
185 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
188 reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
192 return !!(reg & REG_STATUS_VAL_MASK);
195 static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
198 struct qcom_gpio_bank *priv = dev_get_priv(dev);
199 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
201 /* Set the output value of the gpio */
202 if (priv->lv_mv_type)
203 return pmic_clrsetbits(dev->parent,
204 gpio_base + REG_LV_MV_OUTPUT_CTL,
205 REG_LV_MV_OUTPUT_CTL_MASK,
206 !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
208 return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
209 REG_CTL_OUTPUT_MASK, !!value);
212 static const struct dm_gpio_ops qcom_gpio_ops = {
213 .direction_input = qcom_gpio_direction_input,
214 .direction_output = qcom_gpio_direction_output,
215 .get_value = qcom_gpio_get_value,
216 .set_value = qcom_gpio_set_value,
217 .get_function = qcom_gpio_get_function,
220 static int qcom_gpio_probe(struct udevice *dev)
222 struct qcom_gpio_bank *priv = dev_get_priv(dev);
225 priv->pid = dev_read_addr(dev);
226 if (priv->pid == FDT_ADDR_T_NONE)
227 return log_msg_ret("bad address", -EINVAL);
229 /* Do a sanity check */
230 reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
231 if (reg != REG_TYPE_VAL)
232 return log_msg_ret("bad type", -ENXIO);
234 reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
235 if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH &&
236 reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV)
237 return log_msg_ret("bad subtype", -ENXIO);
239 priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV ||
240 reg == REG_SUBTYPE_GPIO_MV;
245 static int qcom_gpio_of_to_plat(struct udevice *dev)
247 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
249 uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
250 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
251 if (uc_priv->bank_name == NULL)
252 uc_priv->bank_name = "qcom_pmic";
257 static const struct udevice_id qcom_gpio_ids[] = {
258 { .compatible = "qcom,pm8916-gpio" },
259 { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
260 { .compatible = "qcom,pm8998-gpio" },
261 { .compatible = "qcom,pms405-gpio" },
265 U_BOOT_DRIVER(qcom_pmic_gpio) = {
266 .name = "qcom_pmic_gpio",
268 .of_match = qcom_gpio_ids,
269 .of_to_plat = qcom_gpio_of_to_plat,
270 .probe = qcom_gpio_probe,
271 .ops = &qcom_gpio_ops,
272 .priv_auto = sizeof(struct qcom_gpio_bank),
276 /* Add pmic buttons as GPIO as well - there is no generic way for now */
277 #define PON_INT_RT_STS 0x10
278 #define KPDPWR_ON_INT_BIT 0
279 #define RESIN_ON_INT_BIT 1
281 static int qcom_pwrkey_get_function(struct udevice *dev, unsigned offset)
286 static int qcom_pwrkey_get_value(struct udevice *dev, unsigned offset)
288 struct qcom_gpio_bank *priv = dev_get_priv(dev);
290 int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
296 case 0: /* Power button */
297 return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
299 case 1: /* Reset button */
301 return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
306 static const struct dm_gpio_ops qcom_pwrkey_ops = {
307 .get_value = qcom_pwrkey_get_value,
308 .get_function = qcom_pwrkey_get_function,
311 static int qcom_pwrkey_probe(struct udevice *dev)
313 struct qcom_gpio_bank *priv = dev_get_priv(dev);
316 priv->pid = dev_read_addr(dev);
317 if (priv->pid == FDT_ADDR_T_NONE)
318 return log_msg_ret("bad address", -EINVAL);
320 /* Do a sanity check */
321 reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
323 return log_msg_ret("bad type", -ENXIO);
325 reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
326 if ((reg & 0x5) == 0)
327 return log_msg_ret("bad subtype", -ENXIO);
332 static int qcom_pwrkey_of_to_plat(struct udevice *dev)
334 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
336 uc_priv->gpio_count = 2;
337 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
338 if (uc_priv->bank_name == NULL)
339 uc_priv->bank_name = "pwkey_qcom";
344 static const struct udevice_id qcom_pwrkey_ids[] = {
345 { .compatible = "qcom,pm8916-pwrkey" },
346 { .compatible = "qcom,pm8994-pwrkey" },
347 { .compatible = "qcom,pm8998-pwrkey" },
351 U_BOOT_DRIVER(pwrkey_qcom) = {
352 .name = "pwrkey_qcom",
354 .of_match = qcom_pwrkey_ids,
355 .of_to_plat = qcom_pwrkey_of_to_plat,
356 .probe = qcom_pwrkey_probe,
357 .ops = &qcom_pwrkey_ops,
358 .priv_auto = sizeof(struct qcom_gpio_bank),