ARM: Merge for-2635/s5pv210-clock
[deliverable/linux.git] / arch / arm / mach-s5p6440 / gpio.c
1 /* arch/arm/mach-s5p6440/gpio.c
2 *
3 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5P6440 - GPIOlib support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <linux/kernel.h>
14 #include <linux/irq.h>
15 #include <linux/io.h>
16 #include <mach/map.h>
17 #include <mach/gpio.h>
18 #include <mach/regs-gpio.h>
19 #include <plat/gpio-core.h>
20 #include <plat/gpio-cfg.h>
21 #include <plat/gpio-cfg-helpers.h>
22
23 /* GPIO bank summary:
24 *
25 * Bank GPIOs Style SlpCon ExtInt Group
26 * A 6 4Bit Yes 1
27 * B 7 4Bit Yes 1
28 * C 8 4Bit Yes 2
29 * F 2 2Bit Yes 4 [1]
30 * G 7 4Bit Yes 5
31 * H 10 4Bit[2] Yes 6
32 * I 16 2Bit Yes None
33 * J 12 2Bit Yes None
34 * N 16 2Bit No IRQ_EINT
35 * P 8 2Bit Yes 8
36 * R 15 4Bit[2] Yes 8
37 *
38 * [1] BANKF pins 14,15 do not form part of the external interrupt sources
39 * [2] BANK has two control registers, GPxCON0 and GPxCON1
40 */
41
42 static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
43 unsigned int offset)
44 {
45 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
46 void __iomem *base = ourchip->base;
47 void __iomem *regcon = base;
48 unsigned long con;
49
50 switch (offset) {
51 case 6:
52 offset += 1;
53 case 0:
54 case 1:
55 case 2:
56 case 3:
57 case 4:
58 case 5:
59 regcon -= 4;
60 break;
61 default:
62 offset -= 7;
63 break;
64 }
65
66 con = __raw_readl(regcon);
67 con &= ~(0xf << con_4bit_shift(offset));
68 __raw_writel(con, regcon);
69
70 return 0;
71 }
72
73 static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
74 unsigned int offset, int value)
75 {
76 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
77 void __iomem *base = ourchip->base;
78 void __iomem *regcon = base;
79 unsigned long con;
80 unsigned long dat;
81 unsigned con_offset = offset;
82
83 switch (con_offset) {
84 case 6:
85 con_offset += 1;
86 case 0:
87 case 1:
88 case 2:
89 case 3:
90 case 4:
91 case 5:
92 regcon -= 4;
93 break;
94 default:
95 con_offset -= 7;
96 break;
97 }
98
99 con = __raw_readl(regcon);
100 con &= ~(0xf << con_4bit_shift(con_offset));
101 con |= 0x1 << con_4bit_shift(con_offset);
102
103 dat = __raw_readl(base + GPIODAT_OFF);
104 if (value)
105 dat |= 1 << offset;
106 else
107 dat &= ~(1 << offset);
108
109 __raw_writel(con, regcon);
110 __raw_writel(dat, base + GPIODAT_OFF);
111
112 return 0;
113 }
114
115 int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
116 unsigned int off, unsigned int cfg)
117 {
118 void __iomem *reg = chip->base;
119 unsigned int shift;
120 u32 con;
121
122 switch (off) {
123 case 0:
124 case 1:
125 case 2:
126 case 3:
127 case 4:
128 case 5:
129 shift = (off & 7) * 4;
130 reg -= 4;
131 break;
132 case 6:
133 shift = ((off + 1) & 7) * 4;
134 reg -= 4;
135 default:
136 shift = ((off + 1) & 7) * 4;
137 break;
138 }
139
140 if (s3c_gpio_is_cfg_special(cfg)) {
141 cfg &= 0xf;
142 cfg <<= shift;
143 }
144
145 con = __raw_readl(reg);
146 con &= ~(0xf << shift);
147 con |= cfg;
148 __raw_writel(con, reg);
149
150 return 0;
151 }
152
153 static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
154 {
155 .cfg_eint = 0,
156 }, {
157 .cfg_eint = 7,
158 }, {
159 .cfg_eint = 3,
160 .set_config = s5p6440_gpio_setcfg_4bit_rbank,
161 }, {
162 .cfg_eint = 0,
163 .set_config = s3c_gpio_setcfg_s3c24xx,
164 .get_config = s3c_gpio_getcfg_s3c24xx,
165 }, {
166 .cfg_eint = 2,
167 .set_config = s3c_gpio_setcfg_s3c24xx,
168 .get_config = s3c_gpio_getcfg_s3c24xx,
169 }, {
170 .cfg_eint = 3,
171 .set_config = s3c_gpio_setcfg_s3c24xx,
172 .get_config = s3c_gpio_getcfg_s3c24xx,
173 },
174 };
175
176 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
177 {
178 .base = S5P6440_GPA_BASE,
179 .config = &s5p6440_gpio_cfgs[1],
180 .chip = {
181 .base = S5P6440_GPA(0),
182 .ngpio = S5P6440_GPIO_A_NR,
183 .label = "GPA",
184 },
185 }, {
186 .base = S5P6440_GPB_BASE,
187 .config = &s5p6440_gpio_cfgs[1],
188 .chip = {
189 .base = S5P6440_GPB(0),
190 .ngpio = S5P6440_GPIO_B_NR,
191 .label = "GPB",
192 },
193 }, {
194 .base = S5P6440_GPC_BASE,
195 .config = &s5p6440_gpio_cfgs[1],
196 .chip = {
197 .base = S5P6440_GPC(0),
198 .ngpio = S5P6440_GPIO_C_NR,
199 .label = "GPC",
200 },
201 }, {
202 .base = S5P6440_GPG_BASE,
203 .config = &s5p6440_gpio_cfgs[1],
204 .chip = {
205 .base = S5P6440_GPG(0),
206 .ngpio = S5P6440_GPIO_G_NR,
207 .label = "GPG",
208 },
209 },
210 };
211
212 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
213 {
214 .base = S5P6440_GPH_BASE + 0x4,
215 .config = &s5p6440_gpio_cfgs[1],
216 .chip = {
217 .base = S5P6440_GPH(0),
218 .ngpio = S5P6440_GPIO_H_NR,
219 .label = "GPH",
220 },
221 },
222 };
223
224 static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
225 {
226 .base = S5P6440_GPR_BASE + 0x4,
227 .config = &s5p6440_gpio_cfgs[2],
228 .chip = {
229 .base = S5P6440_GPR(0),
230 .ngpio = S5P6440_GPIO_R_NR,
231 .label = "GPR",
232 },
233 },
234 };
235
236 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
237 {
238 .base = S5P6440_GPF_BASE,
239 .config = &s5p6440_gpio_cfgs[5],
240 .chip = {
241 .base = S5P6440_GPF(0),
242 .ngpio = S5P6440_GPIO_F_NR,
243 .label = "GPF",
244 },
245 }, {
246 .base = S5P6440_GPI_BASE,
247 .config = &s5p6440_gpio_cfgs[3],
248 .chip = {
249 .base = S5P6440_GPI(0),
250 .ngpio = S5P6440_GPIO_I_NR,
251 .label = "GPI",
252 },
253 }, {
254 .base = S5P6440_GPJ_BASE,
255 .config = &s5p6440_gpio_cfgs[3],
256 .chip = {
257 .base = S5P6440_GPJ(0),
258 .ngpio = S5P6440_GPIO_J_NR,
259 .label = "GPJ",
260 },
261 }, {
262 .base = S5P6440_GPN_BASE,
263 .config = &s5p6440_gpio_cfgs[4],
264 .chip = {
265 .base = S5P6440_GPN(0),
266 .ngpio = S5P6440_GPIO_N_NR,
267 .label = "GPN",
268 },
269 }, {
270 .base = S5P6440_GPP_BASE,
271 .config = &s5p6440_gpio_cfgs[5],
272 .chip = {
273 .base = S5P6440_GPP(0),
274 .ngpio = S5P6440_GPIO_P_NR,
275 .label = "GPP",
276 },
277 },
278 };
279
280 void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
281 {
282 for (; nr_chips > 0; nr_chips--, chipcfg++) {
283 if (!chipcfg->set_config)
284 chipcfg->set_config = s3c_gpio_setcfg_s3c64xx_4bit;
285 if (!chipcfg->get_config)
286 chipcfg->get_config = s3c_gpio_getcfg_s3c64xx_4bit;
287 if (!chipcfg->set_pull)
288 chipcfg->set_pull = s3c_gpio_setpull_updown;
289 if (!chipcfg->get_pull)
290 chipcfg->get_pull = s3c_gpio_getpull_updown;
291 }
292 }
293
294 static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
295 int nr_chips)
296 {
297 for (; nr_chips > 0; nr_chips--, chip++) {
298 chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
299 chip->chip.direction_output =
300 s5p6440_gpiolib_rbank_4bit2_output;
301 s3c_gpiolib_add(chip);
302 }
303 }
304
305 static int __init s5p6440_gpiolib_init(void)
306 {
307 struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
308 int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
309
310 s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
311 ARRAY_SIZE(s5p6440_gpio_cfgs));
312
313 for (; nr_chips > 0; nr_chips--, chips++)
314 s3c_gpiolib_add(chips);
315
316 samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
317 ARRAY_SIZE(s5p6440_gpio_4bit));
318
319 samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
320 ARRAY_SIZE(s5p6440_gpio_4bit2));
321
322 s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
323 ARRAY_SIZE(gpio_rbank_4bit2));
324
325 return 0;
326 }
327 arch_initcall(s5p6440_gpiolib_init);
This page took 0.059254 seconds and 5 git commands to generate.