xref: /openbmc/u-boot/drivers/gpio/db8500_gpio.c (revision f1cc9776)
184dee301SMathieu J. Poirier /*
284dee301SMathieu J. Poirier  * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
384dee301SMathieu J. Poirier  * The purpose is that GPIO config found in kernel should work by simply
4a187559eSBin Meng  * copy-paste it to U-Boot.
584dee301SMathieu J. Poirier  *
684dee301SMathieu J. Poirier  * Original Linux authors:
784dee301SMathieu J. Poirier  * Copyright (C) 2008,2009 STMicroelectronics
884dee301SMathieu J. Poirier  * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
984dee301SMathieu J. Poirier  *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
1084dee301SMathieu J. Poirier  *
11a187559eSBin Meng  * Ported to U-Boot by:
1284dee301SMathieu J. Poirier  * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
1384dee301SMathieu J. Poirier  *
1484dee301SMathieu J. Poirier  * This program is free software; you can redistribute it and/or modify
1584dee301SMathieu J. Poirier  * it under the terms of the GNU General Public License version 2 as
1684dee301SMathieu J. Poirier  * published by the Free Software Foundation.
1784dee301SMathieu J. Poirier  */
1884dee301SMathieu J. Poirier 
1984dee301SMathieu J. Poirier #include <common.h>
2084dee301SMathieu J. Poirier #include <asm/io.h>
2184dee301SMathieu J. Poirier 
2284dee301SMathieu J. Poirier #include <asm/arch/db8500_gpio.h>
2384dee301SMathieu J. Poirier #include <asm/arch/db8500_pincfg.h>
2484dee301SMathieu J. Poirier #include <linux/compiler.h>
2584dee301SMathieu J. Poirier 
2684dee301SMathieu J. Poirier #define IO_ADDR(x) (void *) (x)
2784dee301SMathieu J. Poirier 
2884dee301SMathieu J. Poirier /*
2984dee301SMathieu J. Poirier  * The GPIO module in the db8500 Systems-on-Chip is an
3084dee301SMathieu J. Poirier  * AMBA device, managing 32 pins and alternate functions. The logic block
3184dee301SMathieu J. Poirier  * is currently only used in the db8500.
3284dee301SMathieu J. Poirier  */
3384dee301SMathieu J. Poirier 
3484dee301SMathieu J. Poirier #define GPIO_TOTAL_PINS		268
3584dee301SMathieu J. Poirier #define GPIO_PINS_PER_BLOCK	32
3684dee301SMathieu J. Poirier #define GPIO_BLOCKS_COUNT	(GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
3784dee301SMathieu J. Poirier #define GPIO_BLOCK(pin)		(((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
3884dee301SMathieu J. Poirier #define GPIO_PIN_WITHIN_BLOCK(pin)	((pin)%(GPIO_PINS_PER_BLOCK))
3984dee301SMathieu J. Poirier 
4084dee301SMathieu J. Poirier /* Register in the logic block */
4184dee301SMathieu J. Poirier #define DB8500_GPIO_DAT		0x00
4284dee301SMathieu J. Poirier #define DB8500_GPIO_DATS	0x04
4384dee301SMathieu J. Poirier #define DB8500_GPIO_DATC	0x08
4484dee301SMathieu J. Poirier #define DB8500_GPIO_PDIS	0x0c
4584dee301SMathieu J. Poirier #define DB8500_GPIO_DIR		0x10
4684dee301SMathieu J. Poirier #define DB8500_GPIO_DIRS	0x14
4784dee301SMathieu J. Poirier #define DB8500_GPIO_DIRC	0x18
4884dee301SMathieu J. Poirier #define DB8500_GPIO_SLPC	0x1c
4984dee301SMathieu J. Poirier #define DB8500_GPIO_AFSLA	0x20
5084dee301SMathieu J. Poirier #define DB8500_GPIO_AFSLB	0x24
5184dee301SMathieu J. Poirier 
5284dee301SMathieu J. Poirier #define DB8500_GPIO_RIMSC	0x40
5384dee301SMathieu J. Poirier #define DB8500_GPIO_FIMSC	0x44
5484dee301SMathieu J. Poirier #define DB8500_GPIO_IS		0x48
5584dee301SMathieu J. Poirier #define DB8500_GPIO_IC		0x4c
5684dee301SMathieu J. Poirier #define DB8500_GPIO_RWIMSC	0x50
5784dee301SMathieu J. Poirier #define DB8500_GPIO_FWIMSC	0x54
5884dee301SMathieu J. Poirier #define DB8500_GPIO_WKS		0x58
5984dee301SMathieu J. Poirier 
get_gpio_addr(unsigned gpio)6084dee301SMathieu J. Poirier static void __iomem *get_gpio_addr(unsigned gpio)
6184dee301SMathieu J. Poirier {
6284dee301SMathieu J. Poirier 	/* Our list of GPIO chips */
6384dee301SMathieu J. Poirier 	static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
6484dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_0_BASE),
6584dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_1_BASE),
6684dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_2_BASE),
6784dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_3_BASE),
6884dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_4_BASE),
6984dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_5_BASE),
7084dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_6_BASE),
7184dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_7_BASE),
7284dee301SMathieu J. Poirier 		IO_ADDR(CFG_GPIO_8_BASE)
7384dee301SMathieu J. Poirier 	};
7484dee301SMathieu J. Poirier 
7584dee301SMathieu J. Poirier 	return gpio_addrs[GPIO_BLOCK(gpio)];
7684dee301SMathieu J. Poirier }
7784dee301SMathieu J. Poirier 
get_gpio_offset(unsigned gpio)7884dee301SMathieu J. Poirier static unsigned get_gpio_offset(unsigned gpio)
7984dee301SMathieu J. Poirier {
8084dee301SMathieu J. Poirier 	return GPIO_PIN_WITHIN_BLOCK(gpio);
8184dee301SMathieu J. Poirier }
8284dee301SMathieu J. Poirier 
8384dee301SMathieu J. Poirier /* Can only be called from config_pin. Don't configure alt-mode directly */
gpio_set_mode(unsigned gpio,enum db8500_gpio_alt mode)8484dee301SMathieu J. Poirier static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
8584dee301SMathieu J. Poirier {
8684dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
8784dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
8884dee301SMathieu J. Poirier 	u32 bit = 1 << offset;
8984dee301SMathieu J. Poirier 	u32 afunc, bfunc;
9084dee301SMathieu J. Poirier 
9184dee301SMathieu J. Poirier 	afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
9284dee301SMathieu J. Poirier 	bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
9384dee301SMathieu J. Poirier 	if (mode & DB8500_GPIO_ALT_A)
9484dee301SMathieu J. Poirier 		afunc |= bit;
9584dee301SMathieu J. Poirier 	if (mode & DB8500_GPIO_ALT_B)
9684dee301SMathieu J. Poirier 		bfunc |= bit;
9784dee301SMathieu J. Poirier 	writel(afunc, addr + DB8500_GPIO_AFSLA);
9884dee301SMathieu J. Poirier 	writel(bfunc, addr + DB8500_GPIO_AFSLB);
9984dee301SMathieu J. Poirier }
10084dee301SMathieu J. Poirier 
10184dee301SMathieu J. Poirier /**
10284dee301SMathieu J. Poirier  * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
10384dee301SMathieu J. Poirier  * @gpio: pin number
10484dee301SMathieu J. Poirier  * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
10584dee301SMathieu J. Poirier  *  and DB8500_GPIO_PULL_NONE
10684dee301SMathieu J. Poirier  *
10784dee301SMathieu J. Poirier  * Enables/disables pull up/down on a specified pin.  This only takes effect if
10884dee301SMathieu J. Poirier  * the pin is configured as an input (either explicitly or by the alternate
10984dee301SMathieu J. Poirier  * function).
11084dee301SMathieu J. Poirier  *
11184dee301SMathieu J. Poirier  * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
11284dee301SMathieu J. Poirier  * configured as an input.  Otherwise, due to the way the controller registers
11384dee301SMathieu J. Poirier  * work, this function will change the value output on the pin.
11484dee301SMathieu J. Poirier  */
db8500_gpio_set_pull(unsigned gpio,enum db8500_gpio_pull pull)11584dee301SMathieu J. Poirier void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
11684dee301SMathieu J. Poirier {
11784dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
11884dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
11984dee301SMathieu J. Poirier 	u32 bit = 1 << offset;
12084dee301SMathieu J. Poirier 	u32 pdis;
12184dee301SMathieu J. Poirier 
12284dee301SMathieu J. Poirier 	pdis = readl(addr + DB8500_GPIO_PDIS);
12384dee301SMathieu J. Poirier 	if (pull == DB8500_GPIO_PULL_NONE)
12484dee301SMathieu J. Poirier 		pdis |= bit;
12584dee301SMathieu J. Poirier 	else
12684dee301SMathieu J. Poirier 		pdis &= ~bit;
12784dee301SMathieu J. Poirier 	writel(pdis, addr + DB8500_GPIO_PDIS);
12884dee301SMathieu J. Poirier 
12984dee301SMathieu J. Poirier 	if (pull == DB8500_GPIO_PULL_UP)
13084dee301SMathieu J. Poirier 		writel(bit, addr + DB8500_GPIO_DATS);
13184dee301SMathieu J. Poirier 	else if (pull == DB8500_GPIO_PULL_DOWN)
13284dee301SMathieu J. Poirier 		writel(bit, addr + DB8500_GPIO_DATC);
13384dee301SMathieu J. Poirier }
13484dee301SMathieu J. Poirier 
db8500_gpio_make_input(unsigned gpio)13584dee301SMathieu J. Poirier void db8500_gpio_make_input(unsigned gpio)
13684dee301SMathieu J. Poirier {
13784dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
13884dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
13984dee301SMathieu J. Poirier 
14084dee301SMathieu J. Poirier 	writel(1 << offset, addr + DB8500_GPIO_DIRC);
14184dee301SMathieu J. Poirier }
14284dee301SMathieu J. Poirier 
db8500_gpio_get_input(unsigned gpio)14384dee301SMathieu J. Poirier int db8500_gpio_get_input(unsigned gpio)
14484dee301SMathieu J. Poirier {
14584dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
14684dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
14784dee301SMathieu J. Poirier 	u32 bit = 1 << offset;
14884dee301SMathieu J. Poirier 
14984dee301SMathieu J. Poirier 	printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
15084dee301SMathieu J. Poirier 		gpio, addr, offset, bit);
15184dee301SMathieu J. Poirier 
15284dee301SMathieu J. Poirier 	return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
15384dee301SMathieu J. Poirier }
15484dee301SMathieu J. Poirier 
db8500_gpio_make_output(unsigned gpio,int val)15584dee301SMathieu J. Poirier void db8500_gpio_make_output(unsigned gpio, int val)
15684dee301SMathieu J. Poirier {
15784dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
15884dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
15984dee301SMathieu J. Poirier 
16084dee301SMathieu J. Poirier 	writel(1 << offset, addr + DB8500_GPIO_DIRS);
16184dee301SMathieu J. Poirier 	db8500_gpio_set_output(gpio, val);
16284dee301SMathieu J. Poirier }
16384dee301SMathieu J. Poirier 
db8500_gpio_set_output(unsigned gpio,int val)16484dee301SMathieu J. Poirier void db8500_gpio_set_output(unsigned gpio, int val)
16584dee301SMathieu J. Poirier {
16684dee301SMathieu J. Poirier 	void __iomem *addr = get_gpio_addr(gpio);
16784dee301SMathieu J. Poirier 	unsigned offset = get_gpio_offset(gpio);
16884dee301SMathieu J. Poirier 
16984dee301SMathieu J. Poirier 	if (val)
17084dee301SMathieu J. Poirier 		writel(1 << offset, addr + DB8500_GPIO_DATS);
17184dee301SMathieu J. Poirier 	else
17284dee301SMathieu J. Poirier 		writel(1 << offset, addr + DB8500_GPIO_DATC);
17384dee301SMathieu J. Poirier }
17484dee301SMathieu J. Poirier 
17584dee301SMathieu J. Poirier /**
17684dee301SMathieu J. Poirier  * config_pin - configure a pin's mux attributes
177*7582ddceSRobert P. J. Day  * @cfg: pin configuration
17884dee301SMathieu J. Poirier  *
17984dee301SMathieu J. Poirier  * Configures a pin's mode (alternate function or GPIO), its pull up status,
18084dee301SMathieu J. Poirier  * and its sleep mode based on the specified configuration.  The @cfg is
18184dee301SMathieu J. Poirier  * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
18284dee301SMathieu J. Poirier  * are constructed using, and can be further enhanced with, the macros in
18384dee301SMathieu J. Poirier  * plat/pincfg.h.
18484dee301SMathieu J. Poirier  *
18584dee301SMathieu J. Poirier  * If a pin's mode is set to GPIO, it is configured as an input to avoid
18684dee301SMathieu J. Poirier  * side-effects.  The gpio can be manipulated later using standard GPIO API
18784dee301SMathieu J. Poirier  * calls.
18884dee301SMathieu J. Poirier  */
config_pin(unsigned long cfg)18984dee301SMathieu J. Poirier static void config_pin(unsigned long cfg)
19084dee301SMathieu J. Poirier {
19184dee301SMathieu J. Poirier 	int pin = PIN_NUM(cfg);
19284dee301SMathieu J. Poirier 	int pull = PIN_PULL(cfg);
19384dee301SMathieu J. Poirier 	int af = PIN_ALT(cfg);
19484dee301SMathieu J. Poirier 	int output = PIN_DIR(cfg);
19584dee301SMathieu J. Poirier 	int val = PIN_VAL(cfg);
19684dee301SMathieu J. Poirier 
19784dee301SMathieu J. Poirier 	if (output)
19884dee301SMathieu J. Poirier 		db8500_gpio_make_output(pin, val);
19984dee301SMathieu J. Poirier 	else {
20084dee301SMathieu J. Poirier 		db8500_gpio_make_input(pin);
20184dee301SMathieu J. Poirier 		db8500_gpio_set_pull(pin, pull);
20284dee301SMathieu J. Poirier 	}
20384dee301SMathieu J. Poirier 
20484dee301SMathieu J. Poirier 	gpio_set_mode(pin, af);
20584dee301SMathieu J. Poirier }
20684dee301SMathieu J. Poirier 
20784dee301SMathieu J. Poirier /**
20884dee301SMathieu J. Poirier  * db8500_config_pins - configure several pins at once
20984dee301SMathieu J. Poirier  * @cfgs: array of pin configurations
21084dee301SMathieu J. Poirier  * @num: number of elments in the array
21184dee301SMathieu J. Poirier  *
21284dee301SMathieu J. Poirier  * Configures several pins using config_pin(). Refer to that function for
21384dee301SMathieu J. Poirier  * further information.
21484dee301SMathieu J. Poirier  */
db8500_gpio_config_pins(unsigned long * cfgs,size_t num)21584dee301SMathieu J. Poirier void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
21684dee301SMathieu J. Poirier {
21784dee301SMathieu J. Poirier 	size_t i;
21884dee301SMathieu J. Poirier 
21984dee301SMathieu J. Poirier 	for (i = 0; i < num; i++)
22084dee301SMathieu J. Poirier 		config_pin(cfgs[i]);
22184dee301SMathieu J. Poirier }
222