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