xref: /openbmc/u-boot/drivers/gpio/omap_gpio.c (revision 63e22517)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2009 Wind River Systems, Inc.
4  * Tom Rix <Tom.Rix@windriver.com>
5  *
6  * This work is derived from the linux 2.6.27 kernel source
7  * To fetch, use the kernel repository
8  * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
9  * Use the v2.6.27 tag.
10  *
11  * Below is the original's header including its copyright
12  *
13  *  linux/arch/arm/plat-omap/gpio.c
14  *
15  * Support functions for OMAP GPIO
16  *
17  * Copyright (C) 2003-2005 Nokia Corporation
18  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
19  */
20 #include <common.h>
21 #include <dm.h>
22 #include <fdtdec.h>
23 #include <asm/gpio.h>
24 #include <asm/io.h>
25 #include <linux/errno.h>
26 #include <malloc.h>
27 
28 DECLARE_GLOBAL_DATA_PTR;
29 
30 #define OMAP_GPIO_DIR_OUT	0
31 #define OMAP_GPIO_DIR_IN	1
32 
33 #ifdef CONFIG_DM_GPIO
34 
35 #define GPIO_PER_BANK			32
36 
37 struct gpio_bank {
38 	/* TODO(sjg@chromium.org): Can we use a struct here? */
39 	void *base;	/* address of registers in physical memory */
40 };
41 
42 #endif
43 
44 static inline int get_gpio_index(int gpio)
45 {
46 	return gpio & 0x1f;
47 }
48 
49 int gpio_is_valid(int gpio)
50 {
51 	return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
52 }
53 
54 static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
55 				int is_input)
56 {
57 	void *reg = bank->base;
58 	u32 l;
59 
60 	reg += OMAP_GPIO_OE;
61 
62 	l = __raw_readl(reg);
63 	if (is_input)
64 		l |= 1 << gpio;
65 	else
66 		l &= ~(1 << gpio);
67 	__raw_writel(l, reg);
68 }
69 
70 /**
71  * Get the direction of the GPIO by reading the GPIO_OE register
72  * corresponding to the specified bank.
73  */
74 static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
75 {
76 	void *reg = bank->base;
77 	u32 v;
78 
79 	reg += OMAP_GPIO_OE;
80 
81 	v = __raw_readl(reg);
82 
83 	if (v & (1 << gpio))
84 		return OMAP_GPIO_DIR_IN;
85 	else
86 		return OMAP_GPIO_DIR_OUT;
87 }
88 
89 static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
90 				int enable)
91 {
92 	void *reg = bank->base;
93 	u32 l = 0;
94 
95 	if (enable)
96 		reg += OMAP_GPIO_SETDATAOUT;
97 	else
98 		reg += OMAP_GPIO_CLEARDATAOUT;
99 
100 	l = 1 << gpio;
101 	__raw_writel(l, reg);
102 }
103 
104 static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
105 {
106 	void *reg = bank->base;
107 	int input;
108 
109 	input = _get_gpio_direction(bank, gpio);
110 	switch (input) {
111 	case OMAP_GPIO_DIR_IN:
112 		reg += OMAP_GPIO_DATAIN;
113 		break;
114 	case OMAP_GPIO_DIR_OUT:
115 		reg += OMAP_GPIO_DATAOUT;
116 		break;
117 	default:
118 		return -1;
119 	}
120 
121 	return (__raw_readl(reg) & (1 << gpio)) != 0;
122 }
123 
124 #ifndef CONFIG_DM_GPIO
125 
126 static inline const struct gpio_bank *get_gpio_bank(int gpio)
127 {
128 	return &omap_gpio_bank[gpio >> 5];
129 }
130 
131 static int check_gpio(int gpio)
132 {
133 	if (!gpio_is_valid(gpio)) {
134 		printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
135 		return -1;
136 	}
137 	return 0;
138 }
139 
140 /**
141  * Set value of the specified gpio
142  */
143 int gpio_set_value(unsigned gpio, int value)
144 {
145 	const struct gpio_bank *bank;
146 
147 	if (check_gpio(gpio) < 0)
148 		return -1;
149 	bank = get_gpio_bank(gpio);
150 	_set_gpio_dataout(bank, get_gpio_index(gpio), value);
151 
152 	return 0;
153 }
154 
155 /**
156  * Get value of the specified gpio
157  */
158 int gpio_get_value(unsigned gpio)
159 {
160 	const struct gpio_bank *bank;
161 
162 	if (check_gpio(gpio) < 0)
163 		return -1;
164 	bank = get_gpio_bank(gpio);
165 
166 	return _get_gpio_value(bank, get_gpio_index(gpio));
167 }
168 
169 /**
170  * Set gpio direction as input
171  */
172 int gpio_direction_input(unsigned gpio)
173 {
174 	const struct gpio_bank *bank;
175 
176 	if (check_gpio(gpio) < 0)
177 		return -1;
178 
179 	bank = get_gpio_bank(gpio);
180 	_set_gpio_direction(bank, get_gpio_index(gpio), 1);
181 
182 	return 0;
183 }
184 
185 /**
186  * Set gpio direction as output
187  */
188 int gpio_direction_output(unsigned gpio, int value)
189 {
190 	const struct gpio_bank *bank;
191 
192 	if (check_gpio(gpio) < 0)
193 		return -1;
194 
195 	bank = get_gpio_bank(gpio);
196 	_set_gpio_dataout(bank, get_gpio_index(gpio), value);
197 	_set_gpio_direction(bank, get_gpio_index(gpio), 0);
198 
199 	return 0;
200 }
201 
202 /**
203  * Request a gpio before using it.
204  *
205  * NOTE: Argument 'label' is unused.
206  */
207 int gpio_request(unsigned gpio, const char *label)
208 {
209 	if (check_gpio(gpio) < 0)
210 		return -1;
211 
212 	return 0;
213 }
214 
215 /**
216  * Reset and free the gpio after using it.
217  */
218 int gpio_free(unsigned gpio)
219 {
220 	return 0;
221 }
222 
223 #else /* new driver model interface CONFIG_DM_GPIO */
224 
225 /* set GPIO pin 'gpio' as an input */
226 static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
227 {
228 	struct gpio_bank *bank = dev_get_priv(dev);
229 
230 	/* Configure GPIO direction as input. */
231 	_set_gpio_direction(bank, offset, 1);
232 
233 	return 0;
234 }
235 
236 /* set GPIO pin 'gpio' as an output, with polarity 'value' */
237 static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
238 				       int value)
239 {
240 	struct gpio_bank *bank = dev_get_priv(dev);
241 
242 	_set_gpio_dataout(bank, offset, value);
243 	_set_gpio_direction(bank, offset, 0);
244 
245 	return 0;
246 }
247 
248 /* read GPIO IN value of pin 'gpio' */
249 static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
250 {
251 	struct gpio_bank *bank = dev_get_priv(dev);
252 
253 	return _get_gpio_value(bank, offset);
254 }
255 
256 /* write GPIO OUT value to pin 'gpio' */
257 static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
258 				 int value)
259 {
260 	struct gpio_bank *bank = dev_get_priv(dev);
261 
262 	_set_gpio_dataout(bank, offset, value);
263 
264 	return 0;
265 }
266 
267 static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
268 {
269 	struct gpio_bank *bank = dev_get_priv(dev);
270 
271 	/* GPIOF_FUNC is not implemented yet */
272 	if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
273 		return GPIOF_OUTPUT;
274 	else
275 		return GPIOF_INPUT;
276 }
277 
278 static const struct dm_gpio_ops gpio_omap_ops = {
279 	.direction_input	= omap_gpio_direction_input,
280 	.direction_output	= omap_gpio_direction_output,
281 	.get_value		= omap_gpio_get_value,
282 	.set_value		= omap_gpio_set_value,
283 	.get_function		= omap_gpio_get_function,
284 };
285 
286 static int omap_gpio_probe(struct udevice *dev)
287 {
288 	struct gpio_bank *bank = dev_get_priv(dev);
289 	struct omap_gpio_platdata *plat = dev_get_platdata(dev);
290 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
291 
292 	uc_priv->bank_name = plat->port_name;
293 	uc_priv->gpio_count = GPIO_PER_BANK;
294 	bank->base = (void *)plat->base;
295 
296 	return 0;
297 }
298 
299 static int omap_gpio_bind(struct udevice *dev)
300 {
301 	struct omap_gpio_platdata *plat = dev_get_platdata(dev);
302 	fdt_addr_t base_addr;
303 
304 	if (plat)
305 		return 0;
306 
307 	base_addr = devfdt_get_addr(dev);
308 	if (base_addr == FDT_ADDR_T_NONE)
309 		return -EINVAL;
310 
311 	/*
312 	* TODO:
313 	* When every board is converted to driver model and DT is
314 	* supported, this can be done by auto-alloc feature, but
315 	* not using calloc to alloc memory for platdata.
316 	*
317 	* For example am33xx_gpio uses platform data rather than device tree.
318 	*
319 	* NOTE: DO NOT COPY this code if you are using device tree.
320 	*/
321 	plat = calloc(1, sizeof(*plat));
322 	if (!plat)
323 		return -ENOMEM;
324 
325 	plat->base = base_addr;
326 	plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
327 	dev->platdata = plat;
328 
329 	return 0;
330 }
331 
332 static const struct udevice_id omap_gpio_ids[] = {
333 	{ .compatible = "ti,omap3-gpio" },
334 	{ .compatible = "ti,omap4-gpio" },
335 	{ .compatible = "ti,am4372-gpio" },
336 	{ }
337 };
338 
339 U_BOOT_DRIVER(gpio_omap) = {
340 	.name	= "gpio_omap",
341 	.id	= UCLASS_GPIO,
342 	.ops	= &gpio_omap_ops,
343 	.of_match = omap_gpio_ids,
344 	.bind	= omap_gpio_bind,
345 	.probe	= omap_gpio_probe,
346 	.priv_auto_alloc_size = sizeof(struct gpio_bank),
347 	.flags = DM_FLAG_PRE_RELOC,
348 };
349 
350 #endif /* CONFIG_DM_GPIO */
351