blob: d5cb383e85e1b08aa3d4f8ca65a9daa85c4119d7 [file] [log] [blame]
Mathieu J. Poirier84dee302012-08-03 11:05:12 +00001/*
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
60static 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
78static 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 */
84static 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 */
115void 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
135void 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
143int 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
155void 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
164void 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 confguration
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 */
189static 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 */
215void 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}