1 /*
2  * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
3  * The purpose is that GPIO config found in kernel should work by simply
4  * copy-paste it to U-Boot.
5  *
6  * Original Linux authors:
7  * Copyright (C) 2008,2009 STMicroelectronics
8  * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
9  *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
10  *
11  * Ported to U-Boot by:
12  * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18 
19 #include <common.h>
20 #include <asm/io.h>
21 
22 #include <asm/arch/db8500_gpio.h>
23 #include <asm/arch/db8500_pincfg.h>
24 #include <linux/compiler.h>
25 
26 #define IO_ADDR(x) (void *) (x)
27 
28 /*
29  * The GPIO module in the db8500 Systems-on-Chip is an
30  * AMBA device, managing 32 pins and alternate functions. The logic block
31  * is currently only used in the db8500.
32  */
33 
34 #define GPIO_TOTAL_PINS		268
35 #define GPIO_PINS_PER_BLOCK	32
36 #define GPIO_BLOCKS_COUNT	(GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
37 #define GPIO_BLOCK(pin)		(((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
38 #define GPIO_PIN_WITHIN_BLOCK(pin)	((pin)%(GPIO_PINS_PER_BLOCK))
39 
40 /* Register in the logic block */
41 #define DB8500_GPIO_DAT		0x00
42 #define DB8500_GPIO_DATS	0x04
43 #define DB8500_GPIO_DATC	0x08
44 #define DB8500_GPIO_PDIS	0x0c
45 #define DB8500_GPIO_DIR		0x10
46 #define DB8500_GPIO_DIRS	0x14
47 #define DB8500_GPIO_DIRC	0x18
48 #define DB8500_GPIO_SLPC	0x1c
49 #define DB8500_GPIO_AFSLA	0x20
50 #define DB8500_GPIO_AFSLB	0x24
51 
52 #define DB8500_GPIO_RIMSC	0x40
53 #define DB8500_GPIO_FIMSC	0x44
54 #define DB8500_GPIO_IS		0x48
55 #define DB8500_GPIO_IC		0x4c
56 #define DB8500_GPIO_RWIMSC	0x50
57 #define DB8500_GPIO_FWIMSC	0x54
58 #define DB8500_GPIO_WKS		0x58
59 
get_gpio_addr(unsigned gpio)60 static void __iomem *get_gpio_addr(unsigned gpio)
61 {
62 	/* Our list of GPIO chips */
63 	static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
64 		IO_ADDR(CFG_GPIO_0_BASE),
65 		IO_ADDR(CFG_GPIO_1_BASE),
66 		IO_ADDR(CFG_GPIO_2_BASE),
67 		IO_ADDR(CFG_GPIO_3_BASE),
68 		IO_ADDR(CFG_GPIO_4_BASE),
69 		IO_ADDR(CFG_GPIO_5_BASE),
70 		IO_ADDR(CFG_GPIO_6_BASE),
71 		IO_ADDR(CFG_GPIO_7_BASE),
72 		IO_ADDR(CFG_GPIO_8_BASE)
73 	};
74 
75 	return gpio_addrs[GPIO_BLOCK(gpio)];
76 }
77 
get_gpio_offset(unsigned gpio)78 static unsigned get_gpio_offset(unsigned gpio)
79 {
80 	return GPIO_PIN_WITHIN_BLOCK(gpio);
81 }
82 
83 /* Can only be called from config_pin. Don't configure alt-mode directly */
gpio_set_mode(unsigned gpio,enum db8500_gpio_alt mode)84 static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
85 {
86 	void __iomem *addr = get_gpio_addr(gpio);
87 	unsigned offset = get_gpio_offset(gpio);
88 	u32 bit = 1 << offset;
89 	u32 afunc, bfunc;
90 
91 	afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
92 	bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
93 	if (mode & DB8500_GPIO_ALT_A)
94 		afunc |= bit;
95 	if (mode & DB8500_GPIO_ALT_B)
96 		bfunc |= bit;
97 	writel(afunc, addr + DB8500_GPIO_AFSLA);
98 	writel(bfunc, addr + DB8500_GPIO_AFSLB);
99 }
100 
101 /**
102  * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
103  * @gpio: pin number
104  * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
105  *  and DB8500_GPIO_PULL_NONE
106  *
107  * Enables/disables pull up/down on a specified pin.  This only takes effect if
108  * the pin is configured as an input (either explicitly or by the alternate
109  * function).
110  *
111  * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
112  * configured as an input.  Otherwise, due to the way the controller registers
113  * work, this function will change the value output on the pin.
114  */
db8500_gpio_set_pull(unsigned gpio,enum db8500_gpio_pull pull)115 void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
116 {
117 	void __iomem *addr = get_gpio_addr(gpio);
118 	unsigned offset = get_gpio_offset(gpio);
119 	u32 bit = 1 << offset;
120 	u32 pdis;
121 
122 	pdis = readl(addr + DB8500_GPIO_PDIS);
123 	if (pull == DB8500_GPIO_PULL_NONE)
124 		pdis |= bit;
125 	else
126 		pdis &= ~bit;
127 	writel(pdis, addr + DB8500_GPIO_PDIS);
128 
129 	if (pull == DB8500_GPIO_PULL_UP)
130 		writel(bit, addr + DB8500_GPIO_DATS);
131 	else if (pull == DB8500_GPIO_PULL_DOWN)
132 		writel(bit, addr + DB8500_GPIO_DATC);
133 }
134 
db8500_gpio_make_input(unsigned gpio)135 void db8500_gpio_make_input(unsigned gpio)
136 {
137 	void __iomem *addr = get_gpio_addr(gpio);
138 	unsigned offset = get_gpio_offset(gpio);
139 
140 	writel(1 << offset, addr + DB8500_GPIO_DIRC);
141 }
142 
db8500_gpio_get_input(unsigned gpio)143 int db8500_gpio_get_input(unsigned gpio)
144 {
145 	void __iomem *addr = get_gpio_addr(gpio);
146 	unsigned offset = get_gpio_offset(gpio);
147 	u32 bit = 1 << offset;
148 
149 	printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
150 		gpio, addr, offset, bit);
151 
152 	return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
153 }
154 
db8500_gpio_make_output(unsigned gpio,int val)155 void db8500_gpio_make_output(unsigned gpio, int val)
156 {
157 	void __iomem *addr = get_gpio_addr(gpio);
158 	unsigned offset = get_gpio_offset(gpio);
159 
160 	writel(1 << offset, addr + DB8500_GPIO_DIRS);
161 	db8500_gpio_set_output(gpio, val);
162 }
163 
db8500_gpio_set_output(unsigned gpio,int val)164 void db8500_gpio_set_output(unsigned gpio, int val)
165 {
166 	void __iomem *addr = get_gpio_addr(gpio);
167 	unsigned offset = get_gpio_offset(gpio);
168 
169 	if (val)
170 		writel(1 << offset, addr + DB8500_GPIO_DATS);
171 	else
172 		writel(1 << offset, addr + DB8500_GPIO_DATC);
173 }
174 
175 /**
176  * config_pin - configure a pin's mux attributes
177  * @cfg: pin configuration
178  *
179  * Configures a pin's mode (alternate function or GPIO), its pull up status,
180  * and its sleep mode based on the specified configuration.  The @cfg is
181  * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
182  * are constructed using, and can be further enhanced with, the macros in
183  * plat/pincfg.h.
184  *
185  * If a pin's mode is set to GPIO, it is configured as an input to avoid
186  * side-effects.  The gpio can be manipulated later using standard GPIO API
187  * calls.
188  */
config_pin(unsigned long cfg)189 static void config_pin(unsigned long cfg)
190 {
191 	int pin = PIN_NUM(cfg);
192 	int pull = PIN_PULL(cfg);
193 	int af = PIN_ALT(cfg);
194 	int output = PIN_DIR(cfg);
195 	int val = PIN_VAL(cfg);
196 
197 	if (output)
198 		db8500_gpio_make_output(pin, val);
199 	else {
200 		db8500_gpio_make_input(pin);
201 		db8500_gpio_set_pull(pin, pull);
202 	}
203 
204 	gpio_set_mode(pin, af);
205 }
206 
207 /**
208  * db8500_config_pins - configure several pins at once
209  * @cfgs: array of pin configurations
210  * @num: number of elments in the array
211  *
212  * Configures several pins using config_pin(). Refer to that function for
213  * further information.
214  */
db8500_gpio_config_pins(unsigned long * cfgs,size_t num)215 void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
216 {
217 	size_t i;
218 
219 	for (i = 0; i < num; i++)
220 		config_pin(cfgs[i]);
221 }
222