1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Qualcomm GPIO driver
4  *
5  * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
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 
msm_gpio_direction_input_special(struct msm_gpio_bank * priv,unsigned int gpio)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 
msm_gpio_direction_input(struct udevice * dev,unsigned int gpio)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 
msm_gpio_set_value_special(struct msm_gpio_bank * priv,unsigned int gpio,int value)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 
msm_gpio_set_value(struct udevice * dev,unsigned int gpio,int value)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 
msm_gpio_direction_output_special(struct msm_gpio_bank * priv,unsigned int gpio,int value)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 
msm_gpio_direction_output(struct udevice * dev,unsigned int gpio,int value)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 
msm_gpio_set_flags(struct udevice * dev,unsigned int gpio,ulong flags)152 static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
153 {
154 	if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
155 		return -EPERM;
156 
157 	if (flags & GPIOD_IS_OUT_ACTIVE) {
158 		return msm_gpio_direction_output(dev, gpio, 1);
159 	} else if (flags & GPIOD_IS_OUT) {
160 		return msm_gpio_direction_output(dev, gpio, 0);
161 	} else if (flags & GPIOD_IS_IN) {
162 		msm_gpio_direction_input(dev, gpio);
163 		if (flags & GPIOD_PULL_UP)
164 			return msm_gpio_set_value(dev, gpio, 1);
165 		else if (flags & GPIOD_PULL_DOWN)
166 			return msm_gpio_set_value(dev, gpio, 0);
167 	}
168 
169 	return 0;
170 }
171 
msm_gpio_get_value_special(struct msm_gpio_bank * priv,unsigned int gpio)172 static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio)
173 {
174 	unsigned int offset = gpio - priv->pin_data->special_pins_start;
175 	const struct msm_special_pin_data *data;
176 
177 	if (!priv->pin_data->special_pins_data)
178 		return -EINVAL;
179 
180 	data = &priv->pin_data->special_pins_data[offset];
181 
182 	if (!data->io_reg)
183 		return -EINVAL;
184 
185 	if (data->in_bit >= 31) {
186 		if (data->out_bit >= 31)
187 			return -EINVAL;
188 
189 		return !!(readl(priv->base + data->io_reg) >> data->out_bit);
190 	}
191 
192 	return !!(readl(priv->base + data->io_reg) >> data->in_bit);
193 }
194 
msm_gpio_get_value(struct udevice * dev,unsigned int gpio)195 static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
196 {
197 	struct msm_gpio_bank *priv = dev_get_priv(dev);
198 
199 	if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
200 		return -EPERM;
201 
202 	if (qcom_is_special_pin(priv->pin_data, gpio))
203 		return msm_gpio_get_value_special(priv, gpio);
204 
205 	return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) & BIT(GPIO_IN));
206 }
207 
msm_gpio_get_function_special(struct msm_gpio_bank * priv,unsigned int gpio)208 static int msm_gpio_get_function_special(struct msm_gpio_bank *priv,
209 					 unsigned int gpio)
210 {
211 	unsigned int offset = gpio - priv->pin_data->special_pins_start;
212 	const struct msm_special_pin_data *data;
213 
214 	if (!priv->pin_data->special_pins_data)
215 		return GPIOF_UNKNOWN;
216 
217 	data = &priv->pin_data->special_pins_data[offset];
218 
219 	/* No I/O fields, cannot control/read the I/O value */
220 	if (!data->io_reg || (data->out_bit >= 31 && data->in_bit >= 31))
221 		return GPIOF_FUNC;
222 
223 	/* No Output-Enable register, cannot control I/O direction */
224 	if (!data->ctl_reg || data->oe_bit >= 31) {
225 		if (data->out_bit >= 31)
226 			return GPIOF_INPUT;
227 		else
228 			return GPIOF_OUTPUT;
229 	}
230 
231 	if (readl(priv->base + data->ctl_reg) & BIT(data->oe_bit))
232 		return GPIOF_OUTPUT;
233 
234 	return GPIOF_INPUT;
235 }
236 
msm_gpio_get_function(struct udevice * dev,unsigned int gpio)237 static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
238 {
239 	struct msm_gpio_bank *priv = dev_get_priv(dev);
240 
241 	if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
242 		return GPIOF_UNKNOWN;
243 
244 	/* Always NOP for special pins, assume they're in the correct state */
245 	if (qcom_is_special_pin(priv->pin_data, gpio))
246 		return msm_gpio_get_function_special(priv, gpio);
247 
248 	if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
249 		return GPIOF_OUTPUT;
250 
251 	return GPIOF_INPUT;
252 }
253 
254 static const struct dm_gpio_ops gpio_msm_ops = {
255 	.set_flags		= msm_gpio_set_flags,
256 	.get_value		= msm_gpio_get_value,
257 	.get_function		= msm_gpio_get_function,
258 };
259 
msm_gpio_probe(struct udevice * dev)260 static int msm_gpio_probe(struct udevice *dev)
261 {
262 	struct msm_gpio_bank *priv = dev_get_priv(dev);
263 
264 	priv->base = dev_read_addr(dev);
265 	priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
266 
267 	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
268 }
269 
msm_gpio_of_to_plat(struct udevice * dev)270 static int msm_gpio_of_to_plat(struct udevice *dev)
271 {
272 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
273 	const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
274 
275 	/* Get the pin count from the pinctrl driver */
276 	uc_priv->gpio_count = pin_data->pin_count;
277 	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
278 					 "gpio-bank-name", NULL);
279 	if (uc_priv->bank_name == NULL)
280 		uc_priv->bank_name = "soc";
281 
282 	return 0;
283 }
284 
285 U_BOOT_DRIVER(gpio_msm) = {
286 	.name	= "gpio_msm",
287 	.id	= UCLASS_GPIO,
288 	.of_to_plat = msm_gpio_of_to_plat,
289 	.probe	= msm_gpio_probe,
290 	.ops	= &gpio_msm_ops,
291 	.flags	= DM_UC_FLAG_SEQ_ALIAS,
292 	.priv_auto	= sizeof(struct msm_gpio_bank),
293 };
294