blob: e5841f5029530f672a977c21cf94b9da08eda5ee [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Mateusz Kulikowski120800d2016-03-31 23:12:31 +02002/*
Sumit Garge555d4c2022-08-04 19:57:17 +05303 * Qualcomm generic pmic gpio driver
Mateusz Kulikowski120800d2016-03-31 23:12:31 +02004 *
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Mateusz Kulikowski120800d2016-03-31 23:12:31 +02006 */
7
8#include <common.h>
9#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020011#include <power/pmic.h>
12#include <spmi/spmi.h>
13#include <asm/io.h>
14#include <asm/gpio.h>
15#include <linux/bitops.h>
16
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020017/* Register offset for each gpio */
18#define REG_OFFSET(x) ((x) * 0x100)
19
20/* Register maps */
21
Sumit Garge555d4c2022-08-04 19:57:17 +053022/* Type and subtype are shared for all PMIC peripherals */
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020023#define REG_TYPE 0x4
24#define REG_SUBTYPE 0x5
25
Sumit Gargcf515842022-08-04 19:57:18 +053026/* 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
34
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020035#define REG_STATUS 0x08
36#define REG_STATUS_VAL_MASK 0x1
37
38/* MODE_CTL */
Jorge Ramirez-Ortize0cc0b62018-01-10 11:33:51 +010039#define REG_CTL 0x40
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020040#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
Sumit Gargcf515842022-08-04 19:57:18 +053045#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
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020049
50#define REG_DIG_VIN_CTL 0x41
51#define REG_DIG_VIN_VIN0 0
52
53#define REG_DIG_PULL_CTL 0x42
54#define REG_DIG_PULL_NO_PU 0x5
55
Sumit Gargcf515842022-08-04 19:57:18 +053056#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
59
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020060#define REG_DIG_OUT_CTL 0x45
61#define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
62#define REG_DIG_OUT_CTL_DRIVE_L 0x1
63
64#define REG_EN_CTL 0x46
65#define REG_EN_CTL_ENABLE (1 << 7)
66
Sumit Garge555d4c2022-08-04 19:57:17 +053067struct qcom_gpio_bank {
Tom Riniaa997d12016-04-12 15:11:23 -040068 uint32_t pid; /* Peripheral ID on SPMI bus */
Sumit Gargcf515842022-08-04 19:57:18 +053069 bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020070};
71
Sumit Garge555d4c2022-08-04 19:57:17 +053072static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
73 bool input, int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020074{
Sumit Garge555d4c2022-08-04 19:57:17 +053075 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020076 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
Sumit Gargcf515842022-08-04 19:57:18 +053077 uint32_t reg_ctl_val;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020078 int ret;
79
80 /* Disable the GPIO */
81 ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
82 REG_EN_CTL_ENABLE, 0);
83 if (ret < 0)
84 return ret;
85
Sumit Gargcf515842022-08-04 19:57:18 +053086 /* Select the mode and output */
87 if (priv->lv_mv_type) {
88 if (input)
89 reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
90 else
91 reg_ctl_val = REG_CTL_LV_MV_MODE_INOUT;
92 } else {
93 if (input)
94 reg_ctl_val = REG_CTL_MODE_INPUT;
95 else
96 reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
97 }
98
99 ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200100 if (ret < 0)
101 return ret;
102
Sumit Gargcf515842022-08-04 19:57:18 +0530103 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);
107 if (ret < 0)
108 return ret;
109 }
110
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200111 /* Set the right pull (no pull) */
112 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
113 REG_DIG_PULL_NO_PU);
114 if (ret < 0)
115 return ret;
116
117 /* Configure output pin drivers if needed */
118 if (!input) {
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,
121 REG_DIG_VIN_VIN0);
122 if (ret < 0)
123 return ret;
124
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);
129 if (ret < 0)
130 return ret;
131 }
132
133 /* Enable the GPIO */
134 return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
135 REG_EN_CTL_ENABLE);
136}
137
Sumit Garge555d4c2022-08-04 19:57:17 +0530138static int qcom_gpio_direction_input(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200139{
Sumit Garge555d4c2022-08-04 19:57:17 +0530140 return qcom_gpio_set_direction(dev, offset, true, 0);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200141}
142
Sumit Garge555d4c2022-08-04 19:57:17 +0530143static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset,
144 int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200145{
Sumit Garge555d4c2022-08-04 19:57:17 +0530146 return qcom_gpio_set_direction(dev, offset, false, value);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200147}
148
Sumit Garge555d4c2022-08-04 19:57:17 +0530149static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200150{
Sumit Garge555d4c2022-08-04 19:57:17 +0530151 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200152 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
153 int reg;
154
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200155 reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
156 if (reg < 0)
157 return reg;
158
Sumit Gargcf515842022-08-04 19:57:18 +0530159 if (priv->lv_mv_type) {
160 switch (reg & REG_CTL_LV_MV_MODE_MASK) {
161 case REG_CTL_LV_MV_MODE_INPUT:
162 return GPIOF_INPUT;
163 case REG_CTL_LV_MV_MODE_INOUT: /* Fallthrough */
164 case REG_CTL_LV_MV_MODE_OUTPUT:
165 return GPIOF_OUTPUT;
166 default:
167 return GPIOF_UNKNOWN;
168 }
169 } else {
170 switch (reg & REG_CTL_MODE_MASK) {
171 case REG_CTL_MODE_INPUT:
172 return GPIOF_INPUT;
173 case REG_CTL_MODE_INOUT: /* Fallthrough */
174 case REG_CTL_MODE_OUTPUT:
175 return GPIOF_OUTPUT;
176 default:
177 return GPIOF_UNKNOWN;
178 }
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200179 }
180}
181
Sumit Garge555d4c2022-08-04 19:57:17 +0530182static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200183{
Sumit Garge555d4c2022-08-04 19:57:17 +0530184 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200185 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
186 int reg;
187
188 reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
189 if (reg < 0)
190 return reg;
191
192 return !!(reg & REG_STATUS_VAL_MASK);
193}
194
Sumit Garge555d4c2022-08-04 19:57:17 +0530195static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
196 int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200197{
Sumit Garge555d4c2022-08-04 19:57:17 +0530198 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200199 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
200
201 /* Set the output value of the gpio */
Sumit Gargcf515842022-08-04 19:57:18 +0530202 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);
207 else
208 return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
209 REG_CTL_OUTPUT_MASK, !!value);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200210}
211
Sumit Garge555d4c2022-08-04 19:57:17 +0530212static 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,
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200218};
219
Sumit Garge555d4c2022-08-04 19:57:17 +0530220static int qcom_gpio_probe(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200221{
Sumit Garge555d4c2022-08-04 19:57:17 +0530222 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200223 int reg;
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100224 u64 pid;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200225
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100226 pid = dev_read_addr(dev);
227 if (pid == FDT_ADDR_T_NONE)
Simon Glassa605b0f2019-09-25 08:55:59 -0600228 return log_msg_ret("bad address", -EINVAL);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200229
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100230 priv->pid = pid;
231
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200232 /* Do a sanity check */
233 reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
Sumit Gargcf515842022-08-04 19:57:18 +0530234 if (reg != REG_TYPE_VAL)
Simon Glassa605b0f2019-09-25 08:55:59 -0600235 return log_msg_ret("bad type", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200236
237 reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
Sumit Gargcf515842022-08-04 19:57:18 +0530238 if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH &&
239 reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV)
Simon Glassa605b0f2019-09-25 08:55:59 -0600240 return log_msg_ret("bad subtype", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200241
Sumit Gargcf515842022-08-04 19:57:18 +0530242 priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV ||
243 reg == REG_SUBTYPE_GPIO_MV;
244
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200245 return 0;
246}
247
Sumit Garge555d4c2022-08-04 19:57:17 +0530248static int qcom_gpio_of_to_plat(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200249{
250 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
251
Simon Glass04048d52017-05-18 20:10:01 -0600252 uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
253 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200254 if (uc_priv->bank_name == NULL)
Sumit Garge555d4c2022-08-04 19:57:17 +0530255 uc_priv->bank_name = "qcom_pmic";
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200256
257 return 0;
258}
259
Sumit Garge555d4c2022-08-04 19:57:17 +0530260static const struct udevice_id qcom_gpio_ids[] = {
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200261 { .compatible = "qcom,pm8916-gpio" },
Jorge Ramirez-Ortize0cc0b62018-01-10 11:33:51 +0100262 { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
Dzmitry Sankouski7964c302021-10-17 13:44:29 +0300263 { .compatible = "qcom,pm8998-gpio" },
Sumit Gargcf515842022-08-04 19:57:18 +0530264 { .compatible = "qcom,pms405-gpio" },
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200265 { }
266};
267
Sumit Garge555d4c2022-08-04 19:57:17 +0530268U_BOOT_DRIVER(qcom_pmic_gpio) = {
269 .name = "qcom_pmic_gpio",
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200270 .id = UCLASS_GPIO,
Sumit Garge555d4c2022-08-04 19:57:17 +0530271 .of_match = qcom_gpio_ids,
272 .of_to_plat = qcom_gpio_of_to_plat,
273 .probe = qcom_gpio_probe,
274 .ops = &qcom_gpio_ops,
275 .priv_auto = sizeof(struct qcom_gpio_bank),
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200276};
277
278
279/* Add pmic buttons as GPIO as well - there is no generic way for now */
280#define PON_INT_RT_STS 0x10
281#define KPDPWR_ON_INT_BIT 0
282#define RESIN_ON_INT_BIT 1
283
Sumit Garge555d4c2022-08-04 19:57:17 +0530284static int qcom_pwrkey_get_function(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200285{
286 return GPIOF_INPUT;
287}
288
Sumit Garge555d4c2022-08-04 19:57:17 +0530289static int qcom_pwrkey_get_value(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200290{
Sumit Garge555d4c2022-08-04 19:57:17 +0530291 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200292
293 int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
294
295 if (reg < 0)
296 return 0;
297
298 switch (offset) {
299 case 0: /* Power button */
300 return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
301 break;
302 case 1: /* Reset button */
303 default:
304 return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
305 break;
306 }
307}
308
Dzmitry Sankouski42a0c902023-01-22 18:21:21 +0300309/*
310 * Since pmic buttons modelled as GPIO, we need empty direction functions
311 * to trick u-boot button driver
312 */
313static int qcom_pwrkey_direction_input(struct udevice *dev, unsigned int offset)
314{
315 return 0;
316}
317
318static int qcom_pwrkey_direction_output(struct udevice *dev, unsigned int offset, int value)
319{
320 return -EOPNOTSUPP;
321}
322
Sumit Garge555d4c2022-08-04 19:57:17 +0530323static const struct dm_gpio_ops qcom_pwrkey_ops = {
324 .get_value = qcom_pwrkey_get_value,
325 .get_function = qcom_pwrkey_get_function,
Dzmitry Sankouski42a0c902023-01-22 18:21:21 +0300326 .direction_input = qcom_pwrkey_direction_input,
327 .direction_output = qcom_pwrkey_direction_output,
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200328};
329
Sumit Garge555d4c2022-08-04 19:57:17 +0530330static int qcom_pwrkey_probe(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200331{
Sumit Garge555d4c2022-08-04 19:57:17 +0530332 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200333 int reg;
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100334 u64 pid;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200335
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100336 pid = dev_read_addr(dev);
337 if (pid == FDT_ADDR_T_NONE)
Simon Glassa605b0f2019-09-25 08:55:59 -0600338 return log_msg_ret("bad address", -EINVAL);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200339
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100340 priv->pid = pid;
341
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200342 /* Do a sanity check */
343 reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
344 if (reg != 0x1)
Simon Glassa605b0f2019-09-25 08:55:59 -0600345 return log_msg_ret("bad type", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200346
347 reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
Dzmitry Sankouski7964c302021-10-17 13:44:29 +0300348 if ((reg & 0x5) == 0)
Simon Glassa605b0f2019-09-25 08:55:59 -0600349 return log_msg_ret("bad subtype", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200350
351 return 0;
352}
353
Sumit Garge555d4c2022-08-04 19:57:17 +0530354static int qcom_pwrkey_of_to_plat(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200355{
356 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
357
358 uc_priv->gpio_count = 2;
Jorge Ramirez-Ortize0cc0b62018-01-10 11:33:51 +0100359 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200360 if (uc_priv->bank_name == NULL)
Sumit Garge555d4c2022-08-04 19:57:17 +0530361 uc_priv->bank_name = "pwkey_qcom";
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200362
363 return 0;
364}
365
Sumit Garge555d4c2022-08-04 19:57:17 +0530366static const struct udevice_id qcom_pwrkey_ids[] = {
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200367 { .compatible = "qcom,pm8916-pwrkey" },
Jorge Ramirez-Ortize0cc0b62018-01-10 11:33:51 +0100368 { .compatible = "qcom,pm8994-pwrkey" },
Dzmitry Sankouski7964c302021-10-17 13:44:29 +0300369 { .compatible = "qcom,pm8998-pwrkey" },
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200370 { }
371};
372
Sumit Garge555d4c2022-08-04 19:57:17 +0530373U_BOOT_DRIVER(pwrkey_qcom) = {
374 .name = "pwrkey_qcom",
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200375 .id = UCLASS_GPIO,
Sumit Garge555d4c2022-08-04 19:57:17 +0530376 .of_match = qcom_pwrkey_ids,
377 .of_to_plat = qcom_pwrkey_of_to_plat,
378 .probe = qcom_pwrkey_probe,
379 .ops = &qcom_pwrkey_ops,
380 .priv_auto = sizeof(struct qcom_gpio_bank),
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200381};