blob: 573b49c0fb73a4e08907c49e29005b00d60d8ee5 [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
Caleb Connolly6a159be2023-10-17 13:48:56 +010067/**
68 * pmic_gpio_match_data - platform specific configuration
69 *
70 * @PMIC_MATCH_NONE: no flags
71 * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them
72 */
73enum pmic_gpio_match_data {
74 PMIC_MATCH_NONE,
75 PMIC_MATCH_READONLY = (1 << 0),
76};
77
Sumit Garge555d4c2022-08-04 19:57:17 +053078struct qcom_gpio_bank {
Tom Riniaa997d12016-04-12 15:11:23 -040079 uint32_t pid; /* Peripheral ID on SPMI bus */
Sumit Gargcf515842022-08-04 19:57:18 +053080 bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020081};
82
Sumit Garge555d4c2022-08-04 19:57:17 +053083static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset,
84 bool input, int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020085{
Sumit Garge555d4c2022-08-04 19:57:17 +053086 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020087 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
Sumit Gargcf515842022-08-04 19:57:18 +053088 uint32_t reg_ctl_val;
Caleb Connolly6a159be2023-10-17 13:48:56 +010089 ulong match_flags = dev_get_driver_data(dev);
90 int ret = 0;
91
92 /* Some PMICs don't like their GPIOs being configured */
93 if (match_flags & PMIC_MATCH_READONLY)
94 return 0;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +020095
96 /* Disable the GPIO */
97 ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
98 REG_EN_CTL_ENABLE, 0);
99 if (ret < 0)
100 return ret;
101
Sumit Gargcf515842022-08-04 19:57:18 +0530102 /* Select the mode and output */
103 if (priv->lv_mv_type) {
104 if (input)
105 reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
106 else
107 reg_ctl_val = REG_CTL_LV_MV_MODE_INOUT;
108 } else {
109 if (input)
110 reg_ctl_val = REG_CTL_MODE_INPUT;
111 else
112 reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
113 }
114
115 ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200116 if (ret < 0)
117 return ret;
118
Sumit Gargcf515842022-08-04 19:57:18 +0530119 if (priv->lv_mv_type && !input) {
120 ret = pmic_reg_write(dev->parent,
121 gpio_base + REG_LV_MV_OUTPUT_CTL,
122 !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
123 if (ret < 0)
124 return ret;
125 }
126
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200127 /* Set the right pull (no pull) */
128 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
129 REG_DIG_PULL_NO_PU);
130 if (ret < 0)
131 return ret;
132
133 /* Configure output pin drivers if needed */
134 if (!input) {
135 /* Select the VIN - VIN0, pin is input so it doesn't matter */
136 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
137 REG_DIG_VIN_VIN0);
138 if (ret < 0)
139 return ret;
140
141 /* Set the right dig out control */
142 ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
143 REG_DIG_OUT_CTL_CMOS |
144 REG_DIG_OUT_CTL_DRIVE_L);
145 if (ret < 0)
146 return ret;
147 }
148
149 /* Enable the GPIO */
150 return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
151 REG_EN_CTL_ENABLE);
152}
153
Sumit Garge555d4c2022-08-04 19:57:17 +0530154static int qcom_gpio_direction_input(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200155{
Sumit Garge555d4c2022-08-04 19:57:17 +0530156 return qcom_gpio_set_direction(dev, offset, true, 0);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200157}
158
Sumit Garge555d4c2022-08-04 19:57:17 +0530159static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset,
160 int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200161{
Sumit Garge555d4c2022-08-04 19:57:17 +0530162 return qcom_gpio_set_direction(dev, offset, false, value);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200163}
164
Sumit Garge555d4c2022-08-04 19:57:17 +0530165static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200166{
Sumit Garge555d4c2022-08-04 19:57:17 +0530167 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200168 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
169 int reg;
170
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200171 reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
172 if (reg < 0)
173 return reg;
174
Sumit Gargcf515842022-08-04 19:57:18 +0530175 if (priv->lv_mv_type) {
176 switch (reg & REG_CTL_LV_MV_MODE_MASK) {
177 case REG_CTL_LV_MV_MODE_INPUT:
178 return GPIOF_INPUT;
179 case REG_CTL_LV_MV_MODE_INOUT: /* Fallthrough */
180 case REG_CTL_LV_MV_MODE_OUTPUT:
181 return GPIOF_OUTPUT;
182 default:
183 return GPIOF_UNKNOWN;
184 }
185 } else {
186 switch (reg & REG_CTL_MODE_MASK) {
187 case REG_CTL_MODE_INPUT:
188 return GPIOF_INPUT;
189 case REG_CTL_MODE_INOUT: /* Fallthrough */
190 case REG_CTL_MODE_OUTPUT:
191 return GPIOF_OUTPUT;
192 default:
193 return GPIOF_UNKNOWN;
194 }
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200195 }
196}
197
Sumit Garge555d4c2022-08-04 19:57:17 +0530198static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200199{
Sumit Garge555d4c2022-08-04 19:57:17 +0530200 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200201 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
202 int reg;
203
204 reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
205 if (reg < 0)
206 return reg;
207
208 return !!(reg & REG_STATUS_VAL_MASK);
209}
210
Sumit Garge555d4c2022-08-04 19:57:17 +0530211static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
212 int value)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200213{
Sumit Garge555d4c2022-08-04 19:57:17 +0530214 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200215 uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
216
217 /* Set the output value of the gpio */
Sumit Gargcf515842022-08-04 19:57:18 +0530218 if (priv->lv_mv_type)
219 return pmic_clrsetbits(dev->parent,
220 gpio_base + REG_LV_MV_OUTPUT_CTL,
221 REG_LV_MV_OUTPUT_CTL_MASK,
222 !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
223 else
224 return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
225 REG_CTL_OUTPUT_MASK, !!value);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200226}
227
Sumit Garge555d4c2022-08-04 19:57:17 +0530228static const struct dm_gpio_ops qcom_gpio_ops = {
229 .direction_input = qcom_gpio_direction_input,
230 .direction_output = qcom_gpio_direction_output,
231 .get_value = qcom_gpio_get_value,
232 .set_value = qcom_gpio_set_value,
233 .get_function = qcom_gpio_get_function,
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200234};
235
Sumit Garge555d4c2022-08-04 19:57:17 +0530236static int qcom_gpio_probe(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200237{
Sumit Garge555d4c2022-08-04 19:57:17 +0530238 struct qcom_gpio_bank *priv = dev_get_priv(dev);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200239 int reg;
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100240 u64 pid;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200241
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100242 pid = dev_read_addr(dev);
243 if (pid == FDT_ADDR_T_NONE)
Simon Glassa605b0f2019-09-25 08:55:59 -0600244 return log_msg_ret("bad address", -EINVAL);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200245
Caleb Connollycc0caaa2023-08-10 19:21:51 +0100246 priv->pid = pid;
247
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200248 /* Do a sanity check */
249 reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
Sumit Gargcf515842022-08-04 19:57:18 +0530250 if (reg != REG_TYPE_VAL)
Simon Glassa605b0f2019-09-25 08:55:59 -0600251 return log_msg_ret("bad type", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200252
253 reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
Sumit Gargcf515842022-08-04 19:57:18 +0530254 if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH &&
255 reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV)
Simon Glassa605b0f2019-09-25 08:55:59 -0600256 return log_msg_ret("bad subtype", -ENXIO);
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200257
Sumit Gargcf515842022-08-04 19:57:18 +0530258 priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV ||
259 reg == REG_SUBTYPE_GPIO_MV;
260
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200261 return 0;
262}
263
Caleb Connollye692d882023-11-30 17:46:08 +0000264/*
265 * Parse basic GPIO count specified via the gpio-ranges property
266 * as specified in Linux devicetrees
267 * Returns < 0 on error, otherwise gpio count
268 */
269static int qcom_gpio_of_parse_ranges(struct udevice *dev)
270{
271 int ret;
272 struct ofnode_phandle_args args;
273
274 ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
275 NULL, 3, 0, &args);
276 if (ret)
277 return log_msg_ret("gpio-ranges", ret);
278
279 return args.args[2];
280}
281
Sumit Garge555d4c2022-08-04 19:57:17 +0530282static int qcom_gpio_of_to_plat(struct udevice *dev)
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200283{
284 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Caleb Connollye692d882023-11-30 17:46:08 +0000285 int ret;
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200286
Caleb Connollybd3056b2023-11-30 19:33:15 +0000287 ret = qcom_gpio_of_parse_ranges(dev);
288 if (ret > 0)
289 uc_priv->gpio_count = ret;
290 else
291 return ret;
Caleb Connollye692d882023-11-30 17:46:08 +0000292
293 uc_priv->bank_name = "pmic";
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200294
295 return 0;
296}
297
Sumit Garge555d4c2022-08-04 19:57:17 +0530298static const struct udevice_id qcom_gpio_ids[] = {
Caleb Connolly6a159be2023-10-17 13:48:56 +0100299 { .compatible = "qcom,pm8916-gpio" },
300 { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
301 { .compatible = "qcom,pm8998-gpio", .data = PMIC_MATCH_READONLY },
302 { .compatible = "qcom,pms405-gpio" },
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200303 { }
304};
305
Sumit Garge555d4c2022-08-04 19:57:17 +0530306U_BOOT_DRIVER(qcom_pmic_gpio) = {
307 .name = "qcom_pmic_gpio",
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200308 .id = UCLASS_GPIO,
Sumit Garge555d4c2022-08-04 19:57:17 +0530309 .of_match = qcom_gpio_ids,
310 .of_to_plat = qcom_gpio_of_to_plat,
311 .probe = qcom_gpio_probe,
312 .ops = &qcom_gpio_ops,
313 .priv_auto = sizeof(struct qcom_gpio_bank),
Mateusz Kulikowski120800d2016-03-31 23:12:31 +0200314};
315