blob: 6eaa0a08a26a914462e425f959aeb092467690c9 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Tom Rix0c872ec2009-05-15 23:48:36 +02002/*
3 * Copyright (c) 2009 Wind River Systems, Inc.
4 * Tom Rix <Tom.Rix@windriver.com>
5 *
Tom Rix0c872ec2009-05-15 23:48:36 +02006 * 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>
Tom Rix0c872ec2009-05-15 23:48:36 +020019 */
20#include <common.h>
Simon Glass5915a2a2014-10-22 21:37:09 -060021#include <dm.h>
Tom Rini0a9e3402015-07-31 19:55:09 -040022#include <fdtdec.h>
Joe Hershberger365d6072011-11-11 15:55:36 -060023#include <asm/gpio.h>
Tom Rix0c872ec2009-05-15 23:48:36 +020024#include <asm/io.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090025#include <linux/errno.h>
Tom Rini0a9e3402015-07-31 19:55:09 -040026#include <malloc.h>
27
28DECLARE_GLOBAL_DATA_PTR;
Tom Rix0c872ec2009-05-15 23:48:36 +020029
Sanjeev Premi81bdc152011-09-08 10:47:25 -040030#define OMAP_GPIO_DIR_OUT 0
31#define OMAP_GPIO_DIR_IN 1
32
Simon Glassbcee8d62019-12-06 21:41:35 -070033#if CONFIG_IS_ENABLED(DM_GPIO)
Simon Glass5915a2a2014-10-22 21:37:09 -060034
Simon Glass5915a2a2014-10-22 21:37:09 -060035#define GPIO_PER_BANK 32
36
37struct gpio_bank {
Simon Glass5915a2a2014-10-22 21:37:09 -060038 /* TODO(sjg@chromium.org): Can we use a struct here? */
39 void *base; /* address of registers in physical memory */
Simon Glass5915a2a2014-10-22 21:37:09 -060040};
41
42#endif
43
Nikita Kiryanovdcee1ab2012-11-27 22:40:57 +000044int gpio_is_valid(int gpio)
Tom Rix0c872ec2009-05-15 23:48:36 +020045{
Axel Lin87bd05d2013-06-21 18:54:25 +080046 return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
Tom Rix0c872ec2009-05-15 23:48:36 +020047}
48
Aneesh V25223a62011-07-21 09:29:29 -040049static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
50 int is_input)
Tom Rix0c872ec2009-05-15 23:48:36 +020051{
52 void *reg = bank->base;
53 u32 l;
54
Tom Rini0a9e3402015-07-31 19:55:09 -040055 reg += OMAP_GPIO_OE;
56
Tom Rix0c872ec2009-05-15 23:48:36 +020057 l = __raw_readl(reg);
58 if (is_input)
59 l |= 1 << gpio;
60 else
61 l &= ~(1 << gpio);
62 __raw_writel(l, reg);
63}
64
Sanjeev Premi81bdc152011-09-08 10:47:25 -040065/**
66 * Get the direction of the GPIO by reading the GPIO_OE register
67 * corresponding to the specified bank.
68 */
69static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
Tom Rix0c872ec2009-05-15 23:48:36 +020070{
Sanjeev Premi81bdc152011-09-08 10:47:25 -040071 void *reg = bank->base;
72 u32 v;
Tom Rix0c872ec2009-05-15 23:48:36 +020073
Tom Rini0a9e3402015-07-31 19:55:09 -040074 reg += OMAP_GPIO_OE;
Sanjeev Premi81bdc152011-09-08 10:47:25 -040075
76 v = __raw_readl(reg);
77
78 if (v & (1 << gpio))
79 return OMAP_GPIO_DIR_IN;
80 else
81 return OMAP_GPIO_DIR_OUT;
Tom Rix0c872ec2009-05-15 23:48:36 +020082}
83
Aneesh V25223a62011-07-21 09:29:29 -040084static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
85 int enable)
Tom Rix0c872ec2009-05-15 23:48:36 +020086{
87 void *reg = bank->base;
88 u32 l = 0;
89
Tom Rini0a9e3402015-07-31 19:55:09 -040090 if (enable)
91 reg += OMAP_GPIO_SETDATAOUT;
92 else
93 reg += OMAP_GPIO_CLEARDATAOUT;
94
95 l = 1 << gpio;
Tom Rix0c872ec2009-05-15 23:48:36 +020096 __raw_writel(l, reg);
97}
98
Simon Glassd57b6112014-10-22 21:37:08 -060099static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
100{
101 void *reg = bank->base;
102 int input;
103
Tom Rini0a9e3402015-07-31 19:55:09 -0400104 input = _get_gpio_direction(bank, gpio);
105 switch (input) {
106 case OMAP_GPIO_DIR_IN:
107 reg += OMAP_GPIO_DATAIN;
108 break;
109 case OMAP_GPIO_DIR_OUT:
110 reg += OMAP_GPIO_DATAOUT;
Simon Glassd57b6112014-10-22 21:37:08 -0600111 break;
112 default:
113 return -1;
114 }
115
116 return (__raw_readl(reg) & (1 << gpio)) != 0;
117}
118
Simon Glassbcee8d62019-12-06 21:41:35 -0700119#if !CONFIG_IS_ENABLED(DM_GPIO)
Tom Rinia37f7652020-06-04 16:01:39 -0400120static inline int get_gpio_index(int gpio)
121{
122 return gpio & 0x1f;
123}
Simon Glass5915a2a2014-10-22 21:37:09 -0600124
Simon Glassd57b6112014-10-22 21:37:08 -0600125static inline const struct gpio_bank *get_gpio_bank(int gpio)
126{
127 return &omap_gpio_bank[gpio >> 5];
128}
129
130static int check_gpio(int gpio)
131{
132 if (!gpio_is_valid(gpio)) {
133 printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
134 return -1;
135 }
136 return 0;
137}
138
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400139/**
140 * Set value of the specified gpio
141 */
Joe Hershberger365d6072011-11-11 15:55:36 -0600142int gpio_set_value(unsigned gpio, int value)
Tom Rix0c872ec2009-05-15 23:48:36 +0200143{
Aneesh V25223a62011-07-21 09:29:29 -0400144 const struct gpio_bank *bank;
Tom Rix0c872ec2009-05-15 23:48:36 +0200145
146 if (check_gpio(gpio) < 0)
Joe Hershberger365d6072011-11-11 15:55:36 -0600147 return -1;
Tom Rix0c872ec2009-05-15 23:48:36 +0200148 bank = get_gpio_bank(gpio);
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400149 _set_gpio_dataout(bank, get_gpio_index(gpio), value);
Joe Hershberger365d6072011-11-11 15:55:36 -0600150
151 return 0;
Tom Rix0c872ec2009-05-15 23:48:36 +0200152}
153
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400154/**
155 * Get value of the specified gpio
156 */
Joe Hershberger365d6072011-11-11 15:55:36 -0600157int gpio_get_value(unsigned gpio)
Tom Rix0c872ec2009-05-15 23:48:36 +0200158{
Aneesh V25223a62011-07-21 09:29:29 -0400159 const struct gpio_bank *bank;
Tom Rix0c872ec2009-05-15 23:48:36 +0200160
161 if (check_gpio(gpio) < 0)
Joe Hershberger365d6072011-11-11 15:55:36 -0600162 return -1;
Tom Rix0c872ec2009-05-15 23:48:36 +0200163 bank = get_gpio_bank(gpio);
Simon Glassd57b6112014-10-22 21:37:08 -0600164
165 return _get_gpio_value(bank, get_gpio_index(gpio));
Tom Rix0c872ec2009-05-15 23:48:36 +0200166}
167
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400168/**
169 * Set gpio direction as input
170 */
171int gpio_direction_input(unsigned gpio)
Joel A Fernandes569919d2011-09-04 11:10:03 -0500172{
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400173 const struct gpio_bank *bank;
Joel A Fernandes569919d2011-09-04 11:10:03 -0500174
175 if (check_gpio(gpio) < 0)
Joe Hershberger365d6072011-11-11 15:55:36 -0600176 return -1;
Joel A Fernandes569919d2011-09-04 11:10:03 -0500177
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400178 bank = get_gpio_bank(gpio);
Tom Rix0c872ec2009-05-15 23:48:36 +0200179 _set_gpio_direction(bank, get_gpio_index(gpio), 1);
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400180
181 return 0;
Tom Rix0c872ec2009-05-15 23:48:36 +0200182}
183
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400184/**
185 * Set gpio direction as output
186 */
187int gpio_direction_output(unsigned gpio, int value)
188{
189 const struct gpio_bank *bank;
190
191 if (check_gpio(gpio) < 0)
Joe Hershberger365d6072011-11-11 15:55:36 -0600192 return -1;
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400193
194 bank = get_gpio_bank(gpio);
195 _set_gpio_dataout(bank, get_gpio_index(gpio), value);
196 _set_gpio_direction(bank, get_gpio_index(gpio), 0);
197
198 return 0;
199}
200
201/**
202 * Request a gpio before using it.
203 *
204 * NOTE: Argument 'label' is unused.
205 */
Joe Hershberger365d6072011-11-11 15:55:36 -0600206int gpio_request(unsigned gpio, const char *label)
Tom Rix0c872ec2009-05-15 23:48:36 +0200207{
208 if (check_gpio(gpio) < 0)
Joe Hershberger365d6072011-11-11 15:55:36 -0600209 return -1;
Tom Rix0c872ec2009-05-15 23:48:36 +0200210
211 return 0;
212}
213
Sanjeev Premi81bdc152011-09-08 10:47:25 -0400214/**
215 * Reset and free the gpio after using it.
216 */
Joe Hershberger365d6072011-11-11 15:55:36 -0600217int gpio_free(unsigned gpio)
Tom Rix0c872ec2009-05-15 23:48:36 +0200218{
Joe Hershberger365d6072011-11-11 15:55:36 -0600219 return 0;
Tom Rix0c872ec2009-05-15 23:48:36 +0200220}
Simon Glass5915a2a2014-10-22 21:37:09 -0600221
222#else /* new driver model interface CONFIG_DM_GPIO */
223
Simon Glass5915a2a2014-10-22 21:37:09 -0600224/* set GPIO pin 'gpio' as an input */
225static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
226{
227 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass5915a2a2014-10-22 21:37:09 -0600228
229 /* Configure GPIO direction as input. */
230 _set_gpio_direction(bank, offset, 1);
231
232 return 0;
233}
234
235/* set GPIO pin 'gpio' as an output, with polarity 'value' */
236static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
237 int value)
238{
239 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass5915a2a2014-10-22 21:37:09 -0600240
241 _set_gpio_dataout(bank, offset, value);
242 _set_gpio_direction(bank, offset, 0);
243
244 return 0;
245}
246
247/* read GPIO IN value of pin 'gpio' */
248static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
249{
250 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass5915a2a2014-10-22 21:37:09 -0600251
252 return _get_gpio_value(bank, offset);
253}
254
255/* write GPIO OUT value to pin 'gpio' */
256static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
257 int value)
258{
259 struct gpio_bank *bank = dev_get_priv(dev);
Simon Glass5915a2a2014-10-22 21:37:09 -0600260
261 _set_gpio_dataout(bank, offset, value);
262
263 return 0;
264}
265
Simon Glass5915a2a2014-10-22 21:37:09 -0600266static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
267{
268 struct gpio_bank *bank = dev_get_priv(dev);
269
Simon Glass5915a2a2014-10-22 21:37:09 -0600270 /* GPIOF_FUNC is not implemented yet */
Axel Lin26c04722015-01-31 22:23:38 +0800271 if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
Simon Glass5915a2a2014-10-22 21:37:09 -0600272 return GPIOF_OUTPUT;
273 else
274 return GPIOF_INPUT;
275}
276
277static const struct dm_gpio_ops gpio_omap_ops = {
Simon Glass5915a2a2014-10-22 21:37:09 -0600278 .direction_input = omap_gpio_direction_input,
279 .direction_output = omap_gpio_direction_output,
280 .get_value = omap_gpio_get_value,
281 .set_value = omap_gpio_set_value,
282 .get_function = omap_gpio_get_function,
Simon Glass5915a2a2014-10-22 21:37:09 -0600283};
284
285static int omap_gpio_probe(struct udevice *dev)
286{
287 struct gpio_bank *bank = dev_get_priv(dev);
288 struct omap_gpio_platdata *plat = dev_get_platdata(dev);
Simon Glasse564f052015-03-05 12:25:20 -0700289 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Adam Fordb4c3fb02018-06-11 20:05:38 -0500290 char name[18], *str;
Simon Glass5915a2a2014-10-22 21:37:09 -0600291
Adam Ford535f46d2018-08-17 14:37:58 -0500292 sprintf(name, "gpio@%4x_", (unsigned int)plat->base);
Adam Fordb4c3fb02018-06-11 20:05:38 -0500293 str = strdup(name);
294 if (!str)
295 return -ENOMEM;
296 uc_priv->bank_name = str;
Simon Glass5915a2a2014-10-22 21:37:09 -0600297 uc_priv->gpio_count = GPIO_PER_BANK;
298 bank->base = (void *)plat->base;
Simon Glass5915a2a2014-10-22 21:37:09 -0600299 return 0;
300}
301
Adam Ford6696de82018-06-10 09:29:51 -0500302#if !CONFIG_IS_ENABLED(OF_CONTROL)
Tom Rini0a9e3402015-07-31 19:55:09 -0400303static int omap_gpio_bind(struct udevice *dev)
304{
Simon Glass4d686042017-09-17 16:54:52 -0600305 struct omap_gpio_platdata *plat = dev_get_platdata(dev);
Tom Rini0a9e3402015-07-31 19:55:09 -0400306 fdt_addr_t base_addr;
307
308 if (plat)
309 return 0;
310
Masahiro Yamada25484932020-07-17 14:36:48 +0900311 base_addr = dev_read_addr(dev);
Tom Rini0a9e3402015-07-31 19:55:09 -0400312 if (base_addr == FDT_ADDR_T_NONE)
Simon Glass7c843192017-09-17 16:54:53 -0600313 return -EINVAL;
Tom Rini0a9e3402015-07-31 19:55:09 -0400314
315 /*
316 * TODO:
317 * When every board is converted to driver model and DT is
318 * supported, this can be done by auto-alloc feature, but
319 * not using calloc to alloc memory for platdata.
Simon Glass4d686042017-09-17 16:54:52 -0600320 *
321 * For example am33xx_gpio uses platform data rather than device tree.
322 *
323 * NOTE: DO NOT COPY this code if you are using device tree.
Tom Rini0a9e3402015-07-31 19:55:09 -0400324 */
325 plat = calloc(1, sizeof(*plat));
326 if (!plat)
327 return -ENOMEM;
328
329 plat->base = base_addr;
Simon Glasse160f7d2017-01-17 16:52:55 -0700330 plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
Tom Rini0a9e3402015-07-31 19:55:09 -0400331 dev->platdata = plat;
332
333 return 0;
334}
Adam Ford6696de82018-06-10 09:29:51 -0500335#endif
Tom Rini0a9e3402015-07-31 19:55:09 -0400336
Adam Ford99571b42018-08-20 20:27:48 -0500337#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
Tom Rini0a9e3402015-07-31 19:55:09 -0400338static const struct udevice_id omap_gpio_ids[] = {
339 { .compatible = "ti,omap3-gpio" },
340 { .compatible = "ti,omap4-gpio" },
341 { .compatible = "ti,am4372-gpio" },
342 { }
343};
344
Adam Ford6696de82018-06-10 09:29:51 -0500345static int omap_gpio_ofdata_to_platdata(struct udevice *dev)
346{
347 struct omap_gpio_platdata *plat = dev_get_platdata(dev);
348 fdt_addr_t addr;
349
Masahiro Yamada25484932020-07-17 14:36:48 +0900350 addr = dev_read_addr(dev);
Adam Ford6696de82018-06-10 09:29:51 -0500351 if (addr == FDT_ADDR_T_NONE)
352 return -EINVAL;
353
354 plat->base = addr;
355 return 0;
356}
357#endif
358
Simon Glass5915a2a2014-10-22 21:37:09 -0600359U_BOOT_DRIVER(gpio_omap) = {
360 .name = "gpio_omap",
361 .id = UCLASS_GPIO,
Adam Ford6696de82018-06-10 09:29:51 -0500362#if CONFIG_IS_ENABLED(OF_CONTROL)
Adam Ford99571b42018-08-20 20:27:48 -0500363#if !CONFIG_IS_ENABLED(OF_PLATDATA)
364 .of_match = omap_gpio_ids,
Adam Ford6696de82018-06-10 09:29:51 -0500365 .ofdata_to_platdata = of_match_ptr(omap_gpio_ofdata_to_platdata),
Adam Ford6696de82018-06-10 09:29:51 -0500366 .platdata_auto_alloc_size = sizeof(struct omap_gpio_platdata),
Adam Ford99571b42018-08-20 20:27:48 -0500367#endif
Adam Ford6696de82018-06-10 09:29:51 -0500368#else
369 .bind = omap_gpio_bind,
370#endif
Simon Glass5915a2a2014-10-22 21:37:09 -0600371 .ops = &gpio_omap_ops,
372 .probe = omap_gpio_probe,
373 .priv_auto_alloc_size = sizeof(struct gpio_bank),
Bin Meng695c4992018-10-24 06:36:30 -0700374#if !CONFIG_IS_ENABLED(OF_CONTROL)
Faiz Abbas8e14ba72018-03-15 21:11:34 +0530375 .flags = DM_FLAG_PRE_RELOC,
Bin Meng695c4992018-10-24 06:36:30 -0700376#endif
Simon Glass5915a2a2014-10-22 21:37:09 -0600377};
378
Simon Glassbcee8d62019-12-06 21:41:35 -0700379#endif /* !DM_GPIO */