blob: 93d18e44a54eb1a5dc57604dc52c795be3b56e3a [file] [log] [blame]
Tom Rixdd2d1cc2009-05-15 23:48:36 +02001/*
2 * Copyright (c) 2009 Wind River Systems, Inc.
3 * Tom Rix <Tom.Rix@windriver.com>
4 *
Wolfgang Denk5064ca42013-07-28 22:12:44 +02005 * SPDX-License-Identifier: GPL-2.0
Tom Rixdd2d1cc2009-05-15 23:48:36 +02006 *
7 * This work is derived from the linux 2.6.27 kernel source
8 * To fetch, use the kernel repository
9 * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
10 * Use the v2.6.27 tag.
11 *
12 * Below is the original's header including its copyright
13 *
14 * linux/arch/arm/plat-omap/gpio.c
15 *
16 * Support functions for OMAP GPIO
17 *
18 * Copyright (C) 2003-2005 Nokia Corporation
19 * Written by Juha Yrjölä <juha.yrjola@nokia.com>
Tom Rixdd2d1cc2009-05-15 23:48:36 +020020 */
21#include <common.h>
Simon Glass1a96d7f2014-10-22 21:37:09 -060022#include <dm.h>
Tom Rini7bc2bca2015-07-31 19:55:09 -040023#include <fdtdec.h>
Joe Hershbergerf8928f12011-11-11 15:55:36 -060024#include <asm/gpio.h>
Tom Rixdd2d1cc2009-05-15 23:48:36 +020025#include <asm/io.h>
26#include <asm/errno.h>
Tom Rini7bc2bca2015-07-31 19:55:09 -040027#include <malloc.h>
Mugunthan V N37224822015-10-13 13:57:16 +053028#include <dt-bindings/gpio/gpio.h>
Tom Rini7bc2bca2015-07-31 19:55:09 -040029
30DECLARE_GLOBAL_DATA_PTR;
Tom Rixdd2d1cc2009-05-15 23:48:36 +020031
Sanjeev Premiea2cf552011-09-08 10:47:25 -040032#define OMAP_GPIO_DIR_OUT 0
33#define OMAP_GPIO_DIR_IN 1
34
Simon Glass1a96d7f2014-10-22 21:37:09 -060035#ifdef CONFIG_DM_GPIO
36
Simon Glass1a96d7f2014-10-22 21:37:09 -060037#define GPIO_PER_BANK 32
38
39struct gpio_bank {
Simon Glass1a96d7f2014-10-22 21:37:09 -060040 /* TODO(sjg@chromium.org): Can we use a struct here? */
41 void *base; /* address of registers in physical memory */
Simon Glass1a96d7f2014-10-22 21:37:09 -060042};
43
44#endif
45
Tom Rixdd2d1cc2009-05-15 23:48:36 +020046static inline int get_gpio_index(int gpio)
47{
48 return gpio & 0x1f;
49}
50
Nikita Kiryanove3cb9c12012-11-27 22:40:57 +000051int gpio_is_valid(int gpio)
Tom Rixdd2d1cc2009-05-15 23:48:36 +020052{
Axel Lin01a461f2013-06-21 18:54:25 +080053 return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
Tom Rixdd2d1cc2009-05-15 23:48:36 +020054}
55
Aneesh V9a390882011-07-21 09:29:29 -040056static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
57 int is_input)
Tom Rixdd2d1cc2009-05-15 23:48:36 +020058{
59 void *reg = bank->base;
60 u32 l;
61
Tom Rini7bc2bca2015-07-31 19:55:09 -040062 reg += OMAP_GPIO_OE;
63
Tom Rixdd2d1cc2009-05-15 23:48:36 +020064 l = __raw_readl(reg);
65 if (is_input)
66 l |= 1 << gpio;
67 else
68 l &= ~(1 << gpio);
69 __raw_writel(l, reg);
70}
71
Sanjeev Premiea2cf552011-09-08 10:47:25 -040072/**
73 * Get the direction of the GPIO by reading the GPIO_OE register
74 * corresponding to the specified bank.
75 */
76static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
Tom Rixdd2d1cc2009-05-15 23:48:36 +020077{
Sanjeev Premiea2cf552011-09-08 10:47:25 -040078 void *reg = bank->base;
79 u32 v;
Tom Rixdd2d1cc2009-05-15 23:48:36 +020080
Tom Rini7bc2bca2015-07-31 19:55:09 -040081 reg += OMAP_GPIO_OE;
Sanjeev Premiea2cf552011-09-08 10:47:25 -040082
83 v = __raw_readl(reg);
84
85 if (v & (1 << gpio))
86 return OMAP_GPIO_DIR_IN;
87 else
88 return OMAP_GPIO_DIR_OUT;
Tom Rixdd2d1cc2009-05-15 23:48:36 +020089}
90
Aneesh V9a390882011-07-21 09:29:29 -040091static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
92 int enable)
Tom Rixdd2d1cc2009-05-15 23:48:36 +020093{
94 void *reg = bank->base;
95 u32 l = 0;
96
Tom Rini7bc2bca2015-07-31 19:55:09 -040097 if (enable)
98 reg += OMAP_GPIO_SETDATAOUT;
99 else
100 reg += OMAP_GPIO_CLEARDATAOUT;
101
102 l = 1 << gpio;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200103 __raw_writel(l, reg);
104}
105
Simon Glassba33a3f2014-10-22 21:37:08 -0600106static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
107{
108 void *reg = bank->base;
109 int input;
110
Tom Rini7bc2bca2015-07-31 19:55:09 -0400111 input = _get_gpio_direction(bank, gpio);
112 switch (input) {
113 case OMAP_GPIO_DIR_IN:
114 reg += OMAP_GPIO_DATAIN;
115 break;
116 case OMAP_GPIO_DIR_OUT:
117 reg += OMAP_GPIO_DATAOUT;
Simon Glassba33a3f2014-10-22 21:37:08 -0600118 break;
119 default:
120 return -1;
121 }
122
123 return (__raw_readl(reg) & (1 << gpio)) != 0;
124}
125
Simon Glass1a96d7f2014-10-22 21:37:09 -0600126#ifndef CONFIG_DM_GPIO
127
Simon Glassba33a3f2014-10-22 21:37:08 -0600128static inline const struct gpio_bank *get_gpio_bank(int gpio)
129{
130 return &omap_gpio_bank[gpio >> 5];
131}
132
133static int check_gpio(int gpio)
134{
135 if (!gpio_is_valid(gpio)) {
136 printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
137 return -1;
138 }
139 return 0;
140}
141
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400142/**
143 * Set value of the specified gpio
144 */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600145int gpio_set_value(unsigned gpio, int value)
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200146{
Aneesh V9a390882011-07-21 09:29:29 -0400147 const struct gpio_bank *bank;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200148
149 if (check_gpio(gpio) < 0)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600150 return -1;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200151 bank = get_gpio_bank(gpio);
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400152 _set_gpio_dataout(bank, get_gpio_index(gpio), value);
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600153
154 return 0;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200155}
156
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400157/**
158 * Get value of the specified gpio
159 */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600160int gpio_get_value(unsigned gpio)
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200161{
Aneesh V9a390882011-07-21 09:29:29 -0400162 const struct gpio_bank *bank;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200163
164 if (check_gpio(gpio) < 0)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600165 return -1;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200166 bank = get_gpio_bank(gpio);
Simon Glassba33a3f2014-10-22 21:37:08 -0600167
168 return _get_gpio_value(bank, get_gpio_index(gpio));
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200169}
170
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400171/**
172 * Set gpio direction as input
173 */
174int gpio_direction_input(unsigned gpio)
Joel A Fernandes46b9c202011-09-04 11:10:03 -0500175{
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400176 const struct gpio_bank *bank;
Joel A Fernandes46b9c202011-09-04 11:10:03 -0500177
178 if (check_gpio(gpio) < 0)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600179 return -1;
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400180
Joel A Fernandes46b9c202011-09-04 11:10:03 -0500181 bank = get_gpio_bank(gpio);
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400182 _set_gpio_direction(bank, get_gpio_index(gpio), 1);
183
184 return 0;
Joel A Fernandes46b9c202011-09-04 11:10:03 -0500185}
186
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400187/**
188 * Set gpio direction as output
189 */
190int gpio_direction_output(unsigned gpio, int value)
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200191{
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400192 const struct gpio_bank *bank;
193
194 if (check_gpio(gpio) < 0)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600195 return -1;
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400196
197 bank = get_gpio_bank(gpio);
198 _set_gpio_dataout(bank, get_gpio_index(gpio), value);
199 _set_gpio_direction(bank, get_gpio_index(gpio), 0);
200
201 return 0;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200202}
203
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400204/**
205 * Request a gpio before using it.
206 *
207 * NOTE: Argument 'label' is unused.
208 */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600209int gpio_request(unsigned gpio, const char *label)
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200210{
211 if (check_gpio(gpio) < 0)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600212 return -1;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200213
214 return 0;
215}
216
Sanjeev Premiea2cf552011-09-08 10:47:25 -0400217/**
218 * Reset and free the gpio after using it.
219 */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600220int gpio_free(unsigned gpio)
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200221{
Simon Glass1a96d7f2014-10-22 21:37:09 -0600222 return 0;
223}
224
225#else /* new driver model interface CONFIG_DM_GPIO */
226
Simon Glass1a96d7f2014-10-22 21:37:09 -0600227/* set GPIO pin 'gpio' as an input */
228static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
229{
230 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass1a96d7f2014-10-22 21:37:09 -0600231
232 /* Configure GPIO direction as input. */
233 _set_gpio_direction(bank, offset, 1);
234
235 return 0;
236}
237
238/* set GPIO pin 'gpio' as an output, with polarity 'value' */
239static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
240 int value)
241{
242 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass1a96d7f2014-10-22 21:37:09 -0600243
244 _set_gpio_dataout(bank, offset, value);
245 _set_gpio_direction(bank, offset, 0);
246
247 return 0;
248}
249
250/* read GPIO IN value of pin 'gpio' */
251static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
252{
253 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass1a96d7f2014-10-22 21:37:09 -0600254
255 return _get_gpio_value(bank, offset);
256}
257
258/* write GPIO OUT value to pin 'gpio' */
259static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
260 int value)
261{
262 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass1a96d7f2014-10-22 21:37:09 -0600263
264 _set_gpio_dataout(bank, offset, value);
265
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600266 return 0;
Tom Rixdd2d1cc2009-05-15 23:48:36 +0200267}
Simon Glass1a96d7f2014-10-22 21:37:09 -0600268
Simon Glass1a96d7f2014-10-22 21:37:09 -0600269static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
270{
271 struct gpio_bank *bank = dev_get_priv(dev);
272
Simon Glass1a96d7f2014-10-22 21:37:09 -0600273 /* GPIOF_FUNC is not implemented yet */
Axel Linbb4ab582015-01-31 22:23:38 +0800274 if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
Simon Glass1a96d7f2014-10-22 21:37:09 -0600275 return GPIOF_OUTPUT;
276 else
277 return GPIOF_INPUT;
278}
279
Mugunthan V N37224822015-10-13 13:57:16 +0530280static int omap_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
281 struct fdtdec_phandle_args *args)
282{
283 desc->offset = args->args[0];
284 desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
285
286 return 0;
287}
288
Simon Glass1a96d7f2014-10-22 21:37:09 -0600289static const struct dm_gpio_ops gpio_omap_ops = {
Simon Glass1a96d7f2014-10-22 21:37:09 -0600290 .direction_input = omap_gpio_direction_input,
291 .direction_output = omap_gpio_direction_output,
292 .get_value = omap_gpio_get_value,
293 .set_value = omap_gpio_set_value,
294 .get_function = omap_gpio_get_function,
Mugunthan V N37224822015-10-13 13:57:16 +0530295 .xlate = omap_gpio_xlate,
Simon Glass1a96d7f2014-10-22 21:37:09 -0600296};
297
298static int omap_gpio_probe(struct udevice *dev)
299{
300 struct gpio_bank *bank = dev_get_priv(dev);
301 struct omap_gpio_platdata *plat = dev_get_platdata(dev);
Simon Glassde0977b2015-03-05 12:25:20 -0700302 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass1a96d7f2014-10-22 21:37:09 -0600303
Tom Rini7bc2bca2015-07-31 19:55:09 -0400304 uc_priv->bank_name = plat->port_name;
Simon Glass1a96d7f2014-10-22 21:37:09 -0600305 uc_priv->gpio_count = GPIO_PER_BANK;
306 bank->base = (void *)plat->base;
Tom Rini7bc2bca2015-07-31 19:55:09 -0400307
308 return 0;
309}
310
311static int omap_gpio_bind(struct udevice *dev)
312{
313 struct omap_gpio_platdata *plat = dev->platdata;
314 fdt_addr_t base_addr;
315
316 if (plat)
317 return 0;
318
319 base_addr = dev_get_addr(dev);
320 if (base_addr == FDT_ADDR_T_NONE)
321 return -ENODEV;
322
323 /*
324 * TODO:
325 * When every board is converted to driver model and DT is
326 * supported, this can be done by auto-alloc feature, but
327 * not using calloc to alloc memory for platdata.
328 */
329 plat = calloc(1, sizeof(*plat));
330 if (!plat)
331 return -ENOMEM;
332
333 plat->base = base_addr;
334 plat->port_name = fdt_get_name(gd->fdt_blob, dev->of_offset, NULL);
335 dev->platdata = plat;
Simon Glass1a96d7f2014-10-22 21:37:09 -0600336
337 return 0;
338}
339
Tom Rini7bc2bca2015-07-31 19:55:09 -0400340static const struct udevice_id omap_gpio_ids[] = {
341 { .compatible = "ti,omap3-gpio" },
342 { .compatible = "ti,omap4-gpio" },
343 { .compatible = "ti,am4372-gpio" },
344 { }
345};
346
Simon Glass1a96d7f2014-10-22 21:37:09 -0600347U_BOOT_DRIVER(gpio_omap) = {
348 .name = "gpio_omap",
349 .id = UCLASS_GPIO,
350 .ops = &gpio_omap_ops,
Tom Rini7bc2bca2015-07-31 19:55:09 -0400351 .of_match = omap_gpio_ids,
352 .bind = omap_gpio_bind,
Simon Glass1a96d7f2014-10-22 21:37:09 -0600353 .probe = omap_gpio_probe,
354 .priv_auto_alloc_size = sizeof(struct gpio_bank),
355};
356
357#endif /* CONFIG_DM_GPIO */