1 // SPDX-License-Identifier: GPL-2.0+
10 #include <asm/global_data.h>
13 #include <mach/gpio.h>
15 DECLARE_GLOBAL_DATA_PTR;
18 #define GPIO_OE_DISABLE (0x0 << 9)
19 #define GPIO_OE_ENABLE (0x1 << 9)
20 #define GPIO_OE_MASK (0x1 << 9)
22 /* GPIO_IN_OUT register shifts. */
26 struct msm_gpio_bank {
28 const struct msm_pin_data *pin_data;
31 #define GPIO_CONFIG_REG(dev, x) \
32 (qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
34 #define GPIO_IN_OUT_REG(dev, x) \
35 (GPIO_CONFIG_REG(dev, x) + 0x4)
37 static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv,
40 unsigned int offset = gpio - priv->pin_data->special_pins_start;
41 const struct msm_special_pin_data *data;
43 if (!priv->pin_data->special_pins_data)
46 data = &priv->pin_data->special_pins_data[offset];
48 if (!data->ctl_reg || data->oe_bit >= 31)
51 /* switch direction */
52 clrsetbits_le32(priv->base + data->ctl_reg,
53 BIT(data->oe_bit), 0);
56 static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
58 struct msm_gpio_bank *priv = dev_get_priv(dev);
60 if (qcom_is_special_pin(priv->pin_data, gpio))
61 msm_gpio_direction_input_special(priv, gpio);
64 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
65 GPIO_OE_MASK, GPIO_OE_DISABLE);
70 static int msm_gpio_set_value_special(struct msm_gpio_bank *priv,
71 unsigned int gpio, int value)
73 unsigned int offset = gpio - priv->pin_data->special_pins_start;
74 const struct msm_special_pin_data *data;
76 if (!priv->pin_data->special_pins_data)
79 data = &priv->pin_data->special_pins_data[offset];
81 if (!data->io_reg || data->out_bit >= 31)
86 writel(value << data->out_bit, priv->base + data->io_reg);
91 static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
93 struct msm_gpio_bank *priv = dev_get_priv(dev);
95 if (qcom_is_special_pin(priv->pin_data, gpio))
96 return msm_gpio_set_value_special(priv, gpio, value);
100 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
105 static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv,
109 unsigned int offset = gpio - priv->pin_data->special_pins_start;
110 const struct msm_special_pin_data *data;
112 if (!priv->pin_data->special_pins_data)
115 data = &priv->pin_data->special_pins_data[offset];
117 if (!data->io_reg || data->out_bit >= 31)
122 writel(value << data->out_bit, priv->base + data->io_reg);
124 if (!data->ctl_reg || data->oe_bit >= 31)
127 /* switch direction */
128 clrsetbits_le32(priv->base + data->ctl_reg,
129 BIT(data->oe_bit), BIT(data->oe_bit));
134 static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
137 struct msm_gpio_bank *priv = dev_get_priv(dev);
139 if (qcom_is_special_pin(priv->pin_data, gpio))
140 return msm_gpio_direction_output_special(priv, gpio, value);
144 writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
145 /* switch direction */
146 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
147 GPIO_OE_MASK, GPIO_OE_ENABLE);
152 static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
154 if (flags & GPIOD_IS_OUT_ACTIVE) {
155 return msm_gpio_direction_output(dev, gpio, 1);
156 } else if (flags & GPIOD_IS_OUT) {
157 return msm_gpio_direction_output(dev, gpio, 0);
158 } else if (flags & GPIOD_IS_IN) {
159 msm_gpio_direction_input(dev, gpio);
160 if (flags & GPIOD_PULL_UP)
161 return msm_gpio_set_value(dev, gpio, 1);
162 else if (flags & GPIOD_PULL_DOWN)
163 return msm_gpio_set_value(dev, gpio, 0);
169 static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio)
171 unsigned int offset = gpio - priv->pin_data->special_pins_start;
172 const struct msm_special_pin_data *data;
174 if (!priv->pin_data->special_pins_data)
177 data = &priv->pin_data->special_pins_data[offset];
179 if (!data->io_reg || data->in_bit >= 31)
182 return !!(readl(priv->base + data->io_reg) >> data->in_bit);
185 static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
187 struct msm_gpio_bank *priv = dev_get_priv(dev);
189 if (qcom_is_special_pin(priv->pin_data, gpio))
190 return msm_gpio_get_value_special(priv, gpio);
192 return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
195 static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
197 struct msm_gpio_bank *priv = dev_get_priv(dev);
199 /* Always NOP for special pins, assume they're in the correct state */
200 if (qcom_is_special_pin(priv->pin_data, gpio))
203 if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
209 static const struct dm_gpio_ops gpio_msm_ops = {
210 .set_flags = msm_gpio_set_flags,
211 .get_value = msm_gpio_get_value,
212 .get_function = msm_gpio_get_function,
215 static int msm_gpio_probe(struct udevice *dev)
217 struct msm_gpio_bank *priv = dev_get_priv(dev);
219 priv->base = dev_read_addr(dev);
220 priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
222 return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
225 static int msm_gpio_of_to_plat(struct udevice *dev)
227 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
228 const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
230 /* Get the pin count from the pinctrl driver */
231 uc_priv->gpio_count = pin_data->pin_count;
232 uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
233 "gpio-bank-name", NULL);
234 if (uc_priv->bank_name == NULL)
235 uc_priv->bank_name = "soc";
240 U_BOOT_DRIVER(gpio_msm) = {
243 .of_to_plat = msm_gpio_of_to_plat,
244 .probe = msm_gpio_probe,
245 .ops = &gpio_msm_ops,
246 .flags = DM_UC_FLAG_SEQ_ALIAS,
247 .priv_auto = sizeof(struct msm_gpio_bank),