]> Git Repo - J-u-boot.git/blob - drivers/gpio/msm_gpio.c
Merge patch series "led: introduce LED boot and activity function"
[J-u-boot.git] / drivers / gpio / msm_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Qualcomm GPIO driver
4  *
5  * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
6  */
7
8 #include <dm.h>
9 #include <errno.h>
10 #include <asm/global_data.h>
11 #include <asm/gpio.h>
12 #include <asm/io.h>
13 #include <mach/gpio.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 /* OE */
18 #define GPIO_OE_DISABLE  (0x0 << 9)
19 #define GPIO_OE_ENABLE   (0x1 << 9)
20 #define GPIO_OE_MASK     (0x1 << 9)
21
22 /* GPIO_IN_OUT register shifts. */
23 #define GPIO_IN          0
24 #define GPIO_OUT         1
25
26 struct msm_gpio_bank {
27         phys_addr_t base;
28         const struct msm_pin_data *pin_data;
29 };
30
31 #define GPIO_CONFIG_REG(dev, x) \
32         (qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
33
34 #define GPIO_IN_OUT_REG(dev, x) \
35         (GPIO_CONFIG_REG(dev, x) + 0x4)
36
37 static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv,
38                                              unsigned int gpio)
39 {
40         unsigned int offset = gpio - priv->pin_data->special_pins_start;
41         const struct msm_special_pin_data *data;
42
43         if (!priv->pin_data->special_pins_data)
44                 return;
45
46         data = &priv->pin_data->special_pins_data[offset];
47
48         if (!data->ctl_reg || data->oe_bit >= 31)
49                 return;
50
51         /* switch direction */
52         clrsetbits_le32(priv->base + data->ctl_reg,
53                         BIT(data->oe_bit), 0);
54 }
55
56 static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
57 {
58         struct msm_gpio_bank *priv = dev_get_priv(dev);
59
60         if (qcom_is_special_pin(priv->pin_data, gpio))
61                 msm_gpio_direction_input_special(priv, gpio);
62
63         /* Disable OE bit */
64         clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
65                         GPIO_OE_MASK, GPIO_OE_DISABLE);
66
67         return;
68 }
69
70 static int msm_gpio_set_value_special(struct msm_gpio_bank *priv,
71                                       unsigned int gpio, int value)
72 {
73         unsigned int offset = gpio - priv->pin_data->special_pins_start;
74         const struct msm_special_pin_data *data;
75
76         if (!priv->pin_data->special_pins_data)
77                 return 0;
78
79         data = &priv->pin_data->special_pins_data[offset];
80
81         if (!data->io_reg || data->out_bit >= 31)
82                 return 0;
83
84         value = !!value;
85         /* set value */
86         writel(value << data->out_bit, priv->base + data->io_reg);
87
88         return 0;
89 }
90
91 static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value)
92 {
93         struct msm_gpio_bank *priv = dev_get_priv(dev);
94
95         if (qcom_is_special_pin(priv->pin_data, gpio))
96                 return msm_gpio_set_value_special(priv, gpio, value);
97
98         value = !!value;
99         /* set value */
100         writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
101
102         return 0;
103 }
104
105 static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv,
106                                              unsigned int gpio,
107                                              int value)
108 {
109         unsigned int offset = gpio - priv->pin_data->special_pins_start;
110         const struct msm_special_pin_data *data;
111
112         if (!priv->pin_data->special_pins_data)
113                 return 0;
114
115         data = &priv->pin_data->special_pins_data[offset];
116
117         if (!data->io_reg || data->out_bit >= 31)
118                 return 0;
119
120         value = !!value;
121         /* set value */
122         writel(value << data->out_bit, priv->base + data->io_reg);
123
124         if (!data->ctl_reg || data->oe_bit >= 31)
125                 return 0;
126
127         /* switch direction */
128         clrsetbits_le32(priv->base + data->ctl_reg,
129                         BIT(data->oe_bit), BIT(data->oe_bit));
130
131         return 0;
132 }
133
134 static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
135                                      int value)
136 {
137         struct msm_gpio_bank *priv = dev_get_priv(dev);
138
139         if (qcom_is_special_pin(priv->pin_data, gpio))
140                 return msm_gpio_direction_output_special(priv, gpio, value);
141
142         value = !!value;
143         /* set 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);
148
149         return 0;
150 }
151
152 static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
153 {
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);
164         }
165
166         return 0;
167 }
168
169 static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio)
170 {
171         unsigned int offset = gpio - priv->pin_data->special_pins_start;
172         const struct msm_special_pin_data *data;
173
174         if (!priv->pin_data->special_pins_data)
175                 return 0;
176
177         data = &priv->pin_data->special_pins_data[offset];
178
179         if (!data->io_reg || data->in_bit >= 31)
180                 return 0;
181
182         return !!(readl(priv->base + data->io_reg) >> data->in_bit);
183 }
184
185 static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
186 {
187         struct msm_gpio_bank *priv = dev_get_priv(dev);
188
189         if (qcom_is_special_pin(priv->pin_data, gpio))
190                 return msm_gpio_get_value_special(priv, gpio);
191
192         return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
193 }
194
195 static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
196 {
197         struct msm_gpio_bank *priv = dev_get_priv(dev);
198
199         /* Always NOP for special pins, assume they're in the correct state */
200         if (qcom_is_special_pin(priv->pin_data, gpio))
201                 return 0;
202
203         if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
204                 return GPIOF_OUTPUT;
205
206         return GPIOF_INPUT;
207 }
208
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,
213 };
214
215 static int msm_gpio_probe(struct udevice *dev)
216 {
217         struct msm_gpio_bank *priv = dev_get_priv(dev);
218
219         priv->base = dev_read_addr(dev);
220         priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
221
222         return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
223 }
224
225 static int msm_gpio_of_to_plat(struct udevice *dev)
226 {
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);
229
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";
236
237         return 0;
238 }
239
240 U_BOOT_DRIVER(gpio_msm) = {
241         .name   = "gpio_msm",
242         .id     = UCLASS_GPIO,
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),
248 };
This page took 0.03998 seconds and 4 git commands to generate.