xref: /rk3399_rockchip-uboot/drivers/gpio/omap_gpio.c (revision 90d0ce442b2814a193ffd3009d11f4f5aca4d325)
1308252adSMarek Vasut /*
2308252adSMarek Vasut  * Copyright (c) 2009 Wind River Systems, Inc.
3308252adSMarek Vasut  * Tom Rix <Tom.Rix@windriver.com>
4308252adSMarek Vasut  *
5bcd4d4ebSWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0
6308252adSMarek Vasut  *
7308252adSMarek Vasut  * This work is derived from the linux 2.6.27 kernel source
8308252adSMarek Vasut  * To fetch, use the kernel repository
9308252adSMarek Vasut  * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
10308252adSMarek Vasut  * Use the v2.6.27 tag.
11308252adSMarek Vasut  *
12308252adSMarek Vasut  * Below is the original's header including its copyright
13308252adSMarek Vasut  *
14308252adSMarek Vasut  *  linux/arch/arm/plat-omap/gpio.c
15308252adSMarek Vasut  *
16308252adSMarek Vasut  * Support functions for OMAP GPIO
17308252adSMarek Vasut  *
18308252adSMarek Vasut  * Copyright (C) 2003-2005 Nokia Corporation
19308252adSMarek Vasut  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
20308252adSMarek Vasut  */
21308252adSMarek Vasut #include <common.h>
225915a2adSSimon Glass #include <dm.h>
230a9e3405STom Rini #include <fdtdec.h>
24308252adSMarek Vasut #include <asm/gpio.h>
25308252adSMarek Vasut #include <asm/io.h>
261221ce45SMasahiro Yamada #include <linux/errno.h>
270a9e3405STom Rini #include <malloc.h>
280a9e3405STom Rini 
290a9e3405STom Rini DECLARE_GLOBAL_DATA_PTR;
30308252adSMarek Vasut 
31308252adSMarek Vasut #define OMAP_GPIO_DIR_OUT	0
32308252adSMarek Vasut #define OMAP_GPIO_DIR_IN	1
33308252adSMarek Vasut 
345915a2adSSimon Glass #ifdef CONFIG_DM_GPIO
355915a2adSSimon Glass 
365915a2adSSimon Glass #define GPIO_PER_BANK			32
375915a2adSSimon Glass 
385915a2adSSimon Glass struct gpio_bank {
395915a2adSSimon Glass 	/* TODO(sjg@chromium.org): Can we use a struct here? */
405915a2adSSimon Glass 	void *base;	/* address of registers in physical memory */
415915a2adSSimon Glass };
425915a2adSSimon Glass 
435915a2adSSimon Glass #endif
445915a2adSSimon Glass 
get_gpio_index(int gpio)45308252adSMarek Vasut static inline int get_gpio_index(int gpio)
46308252adSMarek Vasut {
47308252adSMarek Vasut 	return gpio & 0x1f;
48308252adSMarek Vasut }
49308252adSMarek Vasut 
gpio_is_valid(int gpio)50dcee1ab3SNikita Kiryanov int gpio_is_valid(int gpio)
51308252adSMarek Vasut {
5287bd05d7SAxel Lin 	return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
53308252adSMarek Vasut }
54308252adSMarek Vasut 
_set_gpio_direction(const struct gpio_bank * bank,int gpio,int is_input)55308252adSMarek Vasut static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
56308252adSMarek Vasut 				int is_input)
57308252adSMarek Vasut {
58308252adSMarek Vasut 	void *reg = bank->base;
59308252adSMarek Vasut 	u32 l;
60308252adSMarek Vasut 
61308252adSMarek Vasut 	reg += OMAP_GPIO_OE;
620a9e3405STom Rini 
63308252adSMarek Vasut 	l = __raw_readl(reg);
64308252adSMarek Vasut 	if (is_input)
65308252adSMarek Vasut 		l |= 1 << gpio;
66308252adSMarek Vasut 	else
67308252adSMarek Vasut 		l &= ~(1 << gpio);
68308252adSMarek Vasut 	__raw_writel(l, reg);
69308252adSMarek Vasut }
70308252adSMarek Vasut 
71308252adSMarek Vasut /**
72308252adSMarek Vasut  * Get the direction of the GPIO by reading the GPIO_OE register
73308252adSMarek Vasut  * corresponding to the specified bank.
74308252adSMarek Vasut  */
_get_gpio_direction(const struct gpio_bank * bank,int gpio)75308252adSMarek Vasut static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
76308252adSMarek Vasut {
77308252adSMarek Vasut 	void *reg = bank->base;
78308252adSMarek Vasut 	u32 v;
79308252adSMarek Vasut 
80308252adSMarek Vasut 	reg += OMAP_GPIO_OE;
81308252adSMarek Vasut 
82308252adSMarek Vasut 	v = __raw_readl(reg);
83308252adSMarek Vasut 
84308252adSMarek Vasut 	if (v & (1 << gpio))
85308252adSMarek Vasut 		return OMAP_GPIO_DIR_IN;
86308252adSMarek Vasut 	else
87308252adSMarek Vasut 		return OMAP_GPIO_DIR_OUT;
88308252adSMarek Vasut }
89308252adSMarek Vasut 
_set_gpio_dataout(const struct gpio_bank * bank,int gpio,int enable)90308252adSMarek Vasut static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
91308252adSMarek Vasut 				int enable)
92308252adSMarek Vasut {
93308252adSMarek Vasut 	void *reg = bank->base;
94308252adSMarek Vasut 	u32 l = 0;
95308252adSMarek Vasut 
96308252adSMarek Vasut 	if (enable)
97308252adSMarek Vasut 		reg += OMAP_GPIO_SETDATAOUT;
98308252adSMarek Vasut 	else
99308252adSMarek Vasut 		reg += OMAP_GPIO_CLEARDATAOUT;
1000a9e3405STom Rini 
101308252adSMarek Vasut 	l = 1 << gpio;
102308252adSMarek Vasut 	__raw_writel(l, reg);
103308252adSMarek Vasut }
104308252adSMarek Vasut 
_get_gpio_value(const struct gpio_bank * bank,int gpio)105d57b6114SSimon Glass static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
106d57b6114SSimon Glass {
107d57b6114SSimon Glass 	void *reg = bank->base;
108d57b6114SSimon Glass 	int input;
109d57b6114SSimon Glass 
110d57b6114SSimon Glass 	input = _get_gpio_direction(bank, gpio);
111d57b6114SSimon Glass 	switch (input) {
112d57b6114SSimon Glass 	case OMAP_GPIO_DIR_IN:
113d57b6114SSimon Glass 		reg += OMAP_GPIO_DATAIN;
114d57b6114SSimon Glass 		break;
115d57b6114SSimon Glass 	case OMAP_GPIO_DIR_OUT:
116d57b6114SSimon Glass 		reg += OMAP_GPIO_DATAOUT;
117d57b6114SSimon Glass 		break;
118d57b6114SSimon Glass 	default:
119d57b6114SSimon Glass 		return -1;
120d57b6114SSimon Glass 	}
121d57b6114SSimon Glass 
122d57b6114SSimon Glass 	return (__raw_readl(reg) & (1 << gpio)) != 0;
123d57b6114SSimon Glass }
124d57b6114SSimon Glass 
1255915a2adSSimon Glass #ifndef CONFIG_DM_GPIO
1265915a2adSSimon Glass 
get_gpio_bank(int gpio)127d57b6114SSimon Glass static inline const struct gpio_bank *get_gpio_bank(int gpio)
128d57b6114SSimon Glass {
129d57b6114SSimon Glass 	return &omap_gpio_bank[gpio >> 5];
130d57b6114SSimon Glass }
131d57b6114SSimon Glass 
check_gpio(int gpio)132d57b6114SSimon Glass static int check_gpio(int gpio)
133d57b6114SSimon Glass {
134d57b6114SSimon Glass 	if (!gpio_is_valid(gpio)) {
135d57b6114SSimon Glass 		printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
136d57b6114SSimon Glass 		return -1;
137d57b6114SSimon Glass 	}
138d57b6114SSimon Glass 	return 0;
139d57b6114SSimon Glass }
140d57b6114SSimon Glass 
141308252adSMarek Vasut /**
142308252adSMarek Vasut  * Set value of the specified gpio
143308252adSMarek Vasut  */
gpio_set_value(unsigned gpio,int value)144308252adSMarek Vasut int gpio_set_value(unsigned gpio, int value)
145308252adSMarek Vasut {
146308252adSMarek Vasut 	const struct gpio_bank *bank;
147308252adSMarek Vasut 
148308252adSMarek Vasut 	if (check_gpio(gpio) < 0)
149308252adSMarek Vasut 		return -1;
150308252adSMarek Vasut 	bank = get_gpio_bank(gpio);
151308252adSMarek Vasut 	_set_gpio_dataout(bank, get_gpio_index(gpio), value);
152308252adSMarek Vasut 
153308252adSMarek Vasut 	return 0;
154308252adSMarek Vasut }
155308252adSMarek Vasut 
156308252adSMarek Vasut /**
157308252adSMarek Vasut  * Get value of the specified gpio
158308252adSMarek Vasut  */
gpio_get_value(unsigned gpio)159308252adSMarek Vasut int gpio_get_value(unsigned gpio)
160308252adSMarek Vasut {
161308252adSMarek Vasut 	const struct gpio_bank *bank;
162308252adSMarek Vasut 
163308252adSMarek Vasut 	if (check_gpio(gpio) < 0)
164308252adSMarek Vasut 		return -1;
165308252adSMarek Vasut 	bank = get_gpio_bank(gpio);
166d57b6114SSimon Glass 
167d57b6114SSimon Glass 	return _get_gpio_value(bank, get_gpio_index(gpio));
168308252adSMarek Vasut }
169308252adSMarek Vasut 
170308252adSMarek Vasut /**
171308252adSMarek Vasut  * Set gpio direction as input
172308252adSMarek Vasut  */
gpio_direction_input(unsigned gpio)173308252adSMarek Vasut int gpio_direction_input(unsigned gpio)
174308252adSMarek Vasut {
175308252adSMarek Vasut 	const struct gpio_bank *bank;
176308252adSMarek Vasut 
177308252adSMarek Vasut 	if (check_gpio(gpio) < 0)
178308252adSMarek Vasut 		return -1;
179308252adSMarek Vasut 
180308252adSMarek Vasut 	bank = get_gpio_bank(gpio);
181308252adSMarek Vasut 	_set_gpio_direction(bank, get_gpio_index(gpio), 1);
182308252adSMarek Vasut 
183308252adSMarek Vasut 	return 0;
184308252adSMarek Vasut }
185308252adSMarek Vasut 
186308252adSMarek Vasut /**
187308252adSMarek Vasut  * Set gpio direction as output
188308252adSMarek Vasut  */
gpio_direction_output(unsigned gpio,int value)189308252adSMarek Vasut int gpio_direction_output(unsigned gpio, int value)
190308252adSMarek Vasut {
191308252adSMarek Vasut 	const struct gpio_bank *bank;
192308252adSMarek Vasut 
193308252adSMarek Vasut 	if (check_gpio(gpio) < 0)
194308252adSMarek Vasut 		return -1;
195308252adSMarek Vasut 
196308252adSMarek Vasut 	bank = get_gpio_bank(gpio);
197308252adSMarek Vasut 	_set_gpio_dataout(bank, get_gpio_index(gpio), value);
198308252adSMarek Vasut 	_set_gpio_direction(bank, get_gpio_index(gpio), 0);
199308252adSMarek Vasut 
200308252adSMarek Vasut 	return 0;
201308252adSMarek Vasut }
202308252adSMarek Vasut 
203308252adSMarek Vasut /**
204308252adSMarek Vasut  * Request a gpio before using it.
205308252adSMarek Vasut  *
206308252adSMarek Vasut  * NOTE: Argument 'label' is unused.
207308252adSMarek Vasut  */
gpio_request(unsigned gpio,const char * label)208308252adSMarek Vasut int gpio_request(unsigned gpio, const char *label)
209308252adSMarek Vasut {
210308252adSMarek Vasut 	if (check_gpio(gpio) < 0)
211308252adSMarek Vasut 		return -1;
212308252adSMarek Vasut 
213308252adSMarek Vasut 	return 0;
214308252adSMarek Vasut }
215308252adSMarek Vasut 
216308252adSMarek Vasut /**
217308252adSMarek Vasut  * Reset and free the gpio after using it.
218308252adSMarek Vasut  */
gpio_free(unsigned gpio)219308252adSMarek Vasut int gpio_free(unsigned gpio)
220308252adSMarek Vasut {
221308252adSMarek Vasut 	return 0;
222308252adSMarek Vasut }
2235915a2adSSimon Glass 
2245915a2adSSimon Glass #else /* new driver model interface CONFIG_DM_GPIO */
2255915a2adSSimon Glass 
2265915a2adSSimon Glass /* set GPIO pin 'gpio' as an input */
omap_gpio_direction_input(struct udevice * dev,unsigned offset)2275915a2adSSimon Glass static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
2285915a2adSSimon Glass {
2295915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2305915a2adSSimon Glass 
2315915a2adSSimon Glass 	/* Configure GPIO direction as input. */
2325915a2adSSimon Glass 	_set_gpio_direction(bank, offset, 1);
2335915a2adSSimon Glass 
2345915a2adSSimon Glass 	return 0;
2355915a2adSSimon Glass }
2365915a2adSSimon Glass 
2375915a2adSSimon Glass /* set GPIO pin 'gpio' as an output, with polarity 'value' */
omap_gpio_direction_output(struct udevice * dev,unsigned offset,int value)2385915a2adSSimon Glass static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
2395915a2adSSimon Glass 				       int value)
2405915a2adSSimon Glass {
2415915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2425915a2adSSimon Glass 
2435915a2adSSimon Glass 	_set_gpio_dataout(bank, offset, value);
2445915a2adSSimon Glass 	_set_gpio_direction(bank, offset, 0);
2455915a2adSSimon Glass 
2465915a2adSSimon Glass 	return 0;
2475915a2adSSimon Glass }
2485915a2adSSimon Glass 
2495915a2adSSimon Glass /* read GPIO IN value of pin 'gpio' */
omap_gpio_get_value(struct udevice * dev,unsigned offset)2505915a2adSSimon Glass static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
2515915a2adSSimon Glass {
2525915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2535915a2adSSimon Glass 
2545915a2adSSimon Glass 	return _get_gpio_value(bank, offset);
2555915a2adSSimon Glass }
2565915a2adSSimon Glass 
2575915a2adSSimon Glass /* write GPIO OUT value to pin 'gpio' */
omap_gpio_set_value(struct udevice * dev,unsigned offset,int value)2585915a2adSSimon Glass static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
2595915a2adSSimon Glass 				 int value)
2605915a2adSSimon Glass {
2615915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2625915a2adSSimon Glass 
2635915a2adSSimon Glass 	_set_gpio_dataout(bank, offset, value);
2645915a2adSSimon Glass 
2655915a2adSSimon Glass 	return 0;
2665915a2adSSimon Glass }
2675915a2adSSimon Glass 
omap_gpio_get_function(struct udevice * dev,unsigned offset)2685915a2adSSimon Glass static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
2695915a2adSSimon Glass {
2705915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2715915a2adSSimon Glass 
2725915a2adSSimon Glass 	/* GPIOF_FUNC is not implemented yet */
27326c0472cSAxel Lin 	if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
2745915a2adSSimon Glass 		return GPIOF_OUTPUT;
2755915a2adSSimon Glass 	else
2765915a2adSSimon Glass 		return GPIOF_INPUT;
2775915a2adSSimon Glass }
2785915a2adSSimon Glass 
2795915a2adSSimon Glass static const struct dm_gpio_ops gpio_omap_ops = {
2805915a2adSSimon Glass 	.direction_input	= omap_gpio_direction_input,
2815915a2adSSimon Glass 	.direction_output	= omap_gpio_direction_output,
2825915a2adSSimon Glass 	.get_value		= omap_gpio_get_value,
2835915a2adSSimon Glass 	.set_value		= omap_gpio_set_value,
2845915a2adSSimon Glass 	.get_function		= omap_gpio_get_function,
2855915a2adSSimon Glass };
2865915a2adSSimon Glass 
omap_gpio_probe(struct udevice * dev)2875915a2adSSimon Glass static int omap_gpio_probe(struct udevice *dev)
2885915a2adSSimon Glass {
2895915a2adSSimon Glass 	struct gpio_bank *bank = dev_get_priv(dev);
2905915a2adSSimon Glass 	struct omap_gpio_platdata *plat = dev_get_platdata(dev);
291e564f054SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
2925915a2adSSimon Glass 
2930a9e3405STom Rini 	uc_priv->bank_name = plat->port_name;
2945915a2adSSimon Glass 	uc_priv->gpio_count = GPIO_PER_BANK;
2955915a2adSSimon Glass 	bank->base = (void *)plat->base;
2965915a2adSSimon Glass 
2975915a2adSSimon Glass 	return 0;
2985915a2adSSimon Glass }
2995915a2adSSimon Glass 
omap_gpio_bind(struct udevice * dev)3000a9e3405STom Rini static int omap_gpio_bind(struct udevice *dev)
3010a9e3405STom Rini {
3020a9e3405STom Rini 	struct omap_gpio_platdata *plat = dev->platdata;
3030a9e3405STom Rini 	fdt_addr_t base_addr;
3040a9e3405STom Rini 
3050a9e3405STom Rini 	if (plat)
3060a9e3405STom Rini 		return 0;
3070a9e3405STom Rini 
308a821c4afSSimon Glass 	base_addr = devfdt_get_addr(dev);
3090a9e3405STom Rini 	if (base_addr == FDT_ADDR_T_NONE)
310*90d0ce44SSimon Glass 		return -EINVAL;
3110a9e3405STom Rini 
3120a9e3405STom Rini 	/*
3130a9e3405STom Rini 	* TODO:
3140a9e3405STom Rini 	* When every board is converted to driver model and DT is
3150a9e3405STom Rini 	* supported, this can be done by auto-alloc feature, but
3160a9e3405STom Rini 	* not using calloc to alloc memory for platdata.
3170a9e3405STom Rini 	*/
3180a9e3405STom Rini 	plat = calloc(1, sizeof(*plat));
3190a9e3405STom Rini 	if (!plat)
3200a9e3405STom Rini 		return -ENOMEM;
3210a9e3405STom Rini 
3220a9e3405STom Rini 	plat->base = base_addr;
323e160f7d4SSimon Glass 	plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
3240a9e3405STom Rini 	dev->platdata = plat;
3250a9e3405STom Rini 
3260a9e3405STom Rini 	return 0;
3270a9e3405STom Rini }
3280a9e3405STom Rini 
3290a9e3405STom Rini static const struct udevice_id omap_gpio_ids[] = {
3300a9e3405STom Rini 	{ .compatible = "ti,omap3-gpio" },
3310a9e3405STom Rini 	{ .compatible = "ti,omap4-gpio" },
3320a9e3405STom Rini 	{ .compatible = "ti,am4372-gpio" },
3330a9e3405STom Rini 	{ }
3340a9e3405STom Rini };
3350a9e3405STom Rini 
3365915a2adSSimon Glass U_BOOT_DRIVER(gpio_omap) = {
3375915a2adSSimon Glass 	.name	= "gpio_omap",
3385915a2adSSimon Glass 	.id	= UCLASS_GPIO,
3395915a2adSSimon Glass 	.ops	= &gpio_omap_ops,
3400a9e3405STom Rini 	.of_match = omap_gpio_ids,
3410a9e3405STom Rini 	.bind	= omap_gpio_bind,
3425915a2adSSimon Glass 	.probe	= omap_gpio_probe,
3435915a2adSSimon Glass 	.priv_auto_alloc_size = sizeof(struct gpio_bank),
3445915a2adSSimon Glass };
3455915a2adSSimon Glass 
3465915a2adSSimon Glass #endif /* CONFIG_DM_GPIO */
347