• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* arch/arm/plat-s3c64xx/gpiolib.c
2  *
3  * Copyright 2008 Openmoko, Inc.
4  * Copyright 2008 Simtec Electronics
5  *      Ben Dooks <ben@simtec.co.uk>
6  *      http://armlinux.simtec.co.uk/
7  *
8  * S3C64XX - GPIOlib support
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/irq.h>
17 #include <linux/io.h>
18 
19 #include <mach/map.h>
20 #include <mach/gpio.h>
21 #include <mach/gpio-core.h>
22 
23 #include <plat/gpio-cfg.h>
24 #include <plat/gpio-cfg-helpers.h>
25 #include <plat/regs-gpio.h>
26 
27 /* GPIO bank summary:
28  *
29  * Bank	GPIOs	Style	SlpCon	ExtInt Group
30  * A	8	4Bit	Yes	1
31  * B	7	4Bit	Yes	1
32  * C	8	4Bit	Yes	2
33  * D	5	4Bit	Yes	3
34  * E	5	4Bit	Yes	None
35  * F	16	2Bit	Yes	4 [1]
36  * G	7	4Bit	Yes	5
37  * H	10	4Bit[2]	Yes	6
38  * I	16	2Bit	Yes	None
39  * J	12	2Bit	Yes	None
40  * K	16	4Bit[2]	No	None
41  * L	15	4Bit[2] No	None
42  * M	6	4Bit	No	IRQ_EINT
43  * N	16	2Bit	No	IRQ_EINT
44  * O	16	2Bit	Yes	7
45  * P	15	2Bit	Yes	8
46  * Q	9	2Bit	Yes	9
47  *
48  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
49  * [2] BANK has two control registers, GPxCON0 and GPxCON1
50  */
51 
52 #define OFF_GPCON	(0x00)
53 #define OFF_GPDAT	(0x04)
54 
55 #define con_4bit_shift(__off) ((__off) * 4)
56 
57 #if 1
58 #define gpio_dbg(x...) do { } while(0)
59 #else
60 #define gpio_dbg(x...) printk(KERN_DEBUG ## x)
61 #endif
62 
63 /* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
64  * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
65  * following example:
66  *
67  * base + 0x00: Control register, 4 bits per gpio
68  *	        gpio n: 4 bits starting at (4*n)
69  *		0000 = input, 0001 = output, others mean special-function
70  * base + 0x04: Data register, 1 bit per gpio
71  *		bit n: data bit n
72  *
73  * Note, since the data register is one bit per gpio and is at base + 0x4
74  * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
75  * the output.
76 */
77 
s3c64xx_gpiolib_4bit_input(struct gpio_chip * chip,unsigned offset)78 static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
79 {
80 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
81 	void __iomem *base = ourchip->base;
82 	unsigned long con;
83 
84 	con = __raw_readl(base + OFF_GPCON);
85 	con &= ~(0xf << con_4bit_shift(offset));
86 	__raw_writel(con, base + OFF_GPCON);
87 
88 	gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
89 
90 	return 0;
91 }
92 
s3c64xx_gpiolib_4bit_output(struct gpio_chip * chip,unsigned offset,int value)93 static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
94 				       unsigned offset, int value)
95 {
96 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
97 	void __iomem *base = ourchip->base;
98 	unsigned long con;
99 	unsigned long dat;
100 
101 	con = __raw_readl(base + OFF_GPCON);
102 	con &= ~(0xf << con_4bit_shift(offset));
103 	con |= 0x1 << con_4bit_shift(offset);
104 
105 	dat = __raw_readl(base + OFF_GPDAT);
106 	if (value)
107 		dat |= 1 << offset;
108 	else
109 		dat &= ~(1 << offset);
110 
111 	__raw_writel(dat, base + OFF_GPDAT);
112 	__raw_writel(con, base + OFF_GPCON);
113 	__raw_writel(dat, base + OFF_GPDAT);
114 
115 	gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
116 
117 	return 0;
118 }
119 
120 /* The next set of routines are for the case where the GPIO configuration
121  * registers are 4 bits per GPIO but there is more than one register (the
122  * bank has more than 8 GPIOs.
123  *
124  * This case is the similar to the 4 bit case, but the registers are as
125  * follows:
126  *
127  * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
128  *	        gpio n: 4 bits starting at (4*n)
129  *		0000 = input, 0001 = output, others mean special-function
130  * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
131  *	        gpio n: 4 bits starting at (4*n)
132  *		0000 = input, 0001 = output, others mean special-function
133  * base + 0x08: Data register, 1 bit per gpio
134  *		bit n: data bit n
135  *
136  * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
137  * store the 'base + 0x4' address so that these routines see the data
138  * register at ourchip->base + 0x04.
139 */
140 
s3c64xx_gpiolib_4bit2_input(struct gpio_chip * chip,unsigned offset)141 static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
142 {
143 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
144 	void __iomem *base = ourchip->base;
145 	void __iomem *regcon = base;
146 	unsigned long con;
147 
148 	if (offset > 7)
149 		offset -= 8;
150 	else
151 		regcon -= 4;
152 
153 	con = __raw_readl(regcon);
154 	con &= ~(0xf << con_4bit_shift(offset));
155 	__raw_writel(con, regcon);
156 
157 	gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
158 
159 	return 0;
160 
161 }
162 
s3c64xx_gpiolib_4bit2_output(struct gpio_chip * chip,unsigned offset,int value)163 static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
164 				       unsigned offset, int value)
165 {
166 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
167 	void __iomem *base = ourchip->base;
168 	void __iomem *regcon = base;
169 	unsigned long con;
170 	unsigned long dat;
171 
172 	if (offset > 7)
173 		offset -= 8;
174 	else
175 		regcon -= 4;
176 
177 	con = __raw_readl(regcon);
178 	con &= ~(0xf << con_4bit_shift(offset));
179 	con |= 0x1 << con_4bit_shift(offset);
180 
181 	dat = __raw_readl(base + OFF_GPDAT);
182 	if (value)
183 		dat |= 1 << offset;
184 	else
185 		dat &= ~(1 << offset);
186 
187 	__raw_writel(dat, base + OFF_GPDAT);
188 	__raw_writel(con, regcon);
189 	__raw_writel(dat, base + OFF_GPDAT);
190 
191 	gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
192 
193 	return 0;
194 }
195 
196 static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
197 	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
198 	.set_pull	= s3c_gpio_setpull_updown,
199 	.get_pull	= s3c_gpio_getpull_updown,
200 };
201 
202 static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
203 	.cfg_eint	= 7,
204 	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
205 	.set_pull	= s3c_gpio_setpull_updown,
206 	.get_pull	= s3c_gpio_getpull_updown,
207 };
208 
209 static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
210 	.cfg_eint	= 3,
211 	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
212 	.set_pull	= s3c_gpio_setpull_updown,
213 	.get_pull	= s3c_gpio_getpull_updown,
214 };
215 
216 static struct s3c_gpio_chip gpio_4bit[] = {
217 	{
218 		.base	= S3C64XX_GPA_BASE,
219 		.config	= &gpio_4bit_cfg_eint0111,
220 		.chip	= {
221 			.base	= S3C64XX_GPA(0),
222 			.ngpio	= S3C64XX_GPIO_A_NR,
223 			.label	= "GPA",
224 		},
225 	}, {
226 		.base	= S3C64XX_GPB_BASE,
227 		.config	= &gpio_4bit_cfg_eint0111,
228 		.chip	= {
229 			.base	= S3C64XX_GPB(0),
230 			.ngpio	= S3C64XX_GPIO_B_NR,
231 			.label	= "GPB",
232 		},
233 	}, {
234 		.base	= S3C64XX_GPC_BASE,
235 		.config	= &gpio_4bit_cfg_eint0111,
236 		.chip	= {
237 			.base	= S3C64XX_GPC(0),
238 			.ngpio	= S3C64XX_GPIO_C_NR,
239 			.label	= "GPC",
240 		},
241 	}, {
242 		.base	= S3C64XX_GPD_BASE,
243 		.config	= &gpio_4bit_cfg_eint0111,
244 		.chip	= {
245 			.base	= S3C64XX_GPD(0),
246 			.ngpio	= S3C64XX_GPIO_D_NR,
247 			.label	= "GPD",
248 		},
249 	}, {
250 		.base	= S3C64XX_GPE_BASE,
251 		.config	= &gpio_4bit_cfg_noint,
252 		.chip	= {
253 			.base	= S3C64XX_GPE(0),
254 			.ngpio	= S3C64XX_GPIO_E_NR,
255 			.label	= "GPE",
256 		},
257 	}, {
258 		.base	= S3C64XX_GPG_BASE,
259 		.config	= &gpio_4bit_cfg_eint0111,
260 		.chip	= {
261 			.base	= S3C64XX_GPG(0),
262 			.ngpio	= S3C64XX_GPIO_G_NR,
263 			.label	= "GPG",
264 		},
265 	}, {
266 		.base	= S3C64XX_GPM_BASE,
267 		.config	= &gpio_4bit_cfg_eint0011,
268 		.chip	= {
269 			.base	= S3C64XX_GPM(0),
270 			.ngpio	= S3C64XX_GPIO_M_NR,
271 			.label	= "GPM",
272 		},
273 	},
274 };
275 
276 static struct s3c_gpio_chip gpio_4bit2[] = {
277 	{
278 		.base	= S3C64XX_GPH_BASE + 0x4,
279 		.config	= &gpio_4bit_cfg_eint0111,
280 		.chip	= {
281 			.base	= S3C64XX_GPH(0),
282 			.ngpio	= S3C64XX_GPIO_H_NR,
283 			.label	= "GPH",
284 		},
285 	}, {
286 		.base	= S3C64XX_GPK_BASE + 0x4,
287 		.config	= &gpio_4bit_cfg_noint,
288 		.chip	= {
289 			.base	= S3C64XX_GPK(0),
290 			.ngpio	= S3C64XX_GPIO_K_NR,
291 			.label	= "GPK",
292 		},
293 	}, {
294 		.base	= S3C64XX_GPL_BASE + 0x4,
295 		.config	= &gpio_4bit_cfg_eint0011,
296 		.chip	= {
297 			.base	= S3C64XX_GPL(0),
298 			.ngpio	= S3C64XX_GPIO_L_NR,
299 			.label	= "GPL",
300 		},
301 	},
302 };
303 
304 static struct s3c_gpio_cfg gpio_2bit_cfg_noint = {
305 	.set_config	= s3c_gpio_setcfg_s3c24xx,
306 	.set_pull	= s3c_gpio_setpull_updown,
307 	.get_pull	= s3c_gpio_getpull_updown,
308 };
309 
310 static struct s3c_gpio_cfg gpio_2bit_cfg_eint10 = {
311 	.cfg_eint	= 2,
312 	.set_config	= s3c_gpio_setcfg_s3c24xx,
313 	.set_pull	= s3c_gpio_setpull_updown,
314 	.get_pull	= s3c_gpio_getpull_updown,
315 };
316 
317 static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = {
318 	.cfg_eint	= 3,
319 	.set_config	= s3c_gpio_setcfg_s3c24xx,
320 	.set_pull	= s3c_gpio_setpull_updown,
321 	.get_pull	= s3c_gpio_getpull_updown,
322 };
323 
324 static struct s3c_gpio_chip gpio_2bit[] = {
325 	{
326 		.base	= S3C64XX_GPF_BASE,
327 		.config	= &gpio_2bit_cfg_eint11,
328 		.chip	= {
329 			.base	= S3C64XX_GPF(0),
330 			.ngpio	= S3C64XX_GPIO_F_NR,
331 			.label	= "GPF",
332 		},
333 	}, {
334 		.base	= S3C64XX_GPI_BASE,
335 		.config	= &gpio_2bit_cfg_noint,
336 		.chip	= {
337 			.base	= S3C64XX_GPI(0),
338 			.ngpio	= S3C64XX_GPIO_I_NR,
339 			.label	= "GPI",
340 		},
341 	}, {
342 		.base	= S3C64XX_GPJ_BASE,
343 		.config	= &gpio_2bit_cfg_noint,
344 		.chip	= {
345 			.base	= S3C64XX_GPJ(0),
346 			.ngpio	= S3C64XX_GPIO_J_NR,
347 			.label	= "GPJ",
348 		},
349 	}, {
350 		.base	= S3C64XX_GPN_BASE,
351 		.config	= &gpio_2bit_cfg_eint10,
352 		.chip	= {
353 			.base	= S3C64XX_GPN(0),
354 			.ngpio	= S3C64XX_GPIO_N_NR,
355 			.label	= "GPN",
356 		},
357 	}, {
358 		.base	= S3C64XX_GPO_BASE,
359 		.config	= &gpio_2bit_cfg_eint11,
360 		.chip	= {
361 			.base	= S3C64XX_GPO(0),
362 			.ngpio	= S3C64XX_GPIO_O_NR,
363 			.label	= "GPO",
364 		},
365 	}, {
366 		.base	= S3C64XX_GPP_BASE,
367 		.config	= &gpio_2bit_cfg_eint11,
368 		.chip	= {
369 			.base	= S3C64XX_GPP(0),
370 			.ngpio	= S3C64XX_GPIO_P_NR,
371 			.label	= "GPP",
372 		},
373 	}, {
374 		.base	= S3C64XX_GPQ_BASE,
375 		.config	= &gpio_2bit_cfg_eint11,
376 		.chip	= {
377 			.base	= S3C64XX_GPQ(0),
378 			.ngpio	= S3C64XX_GPIO_Q_NR,
379 			.label	= "GPQ",
380 		},
381 	},
382 };
383 
s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip * chip)384 static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
385 {
386 	chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
387 	chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
388 }
389 
s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip * chip)390 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
391 {
392 	chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
393 	chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
394 }
395 
s3c64xx_gpiolib_add(struct s3c_gpio_chip * chips,int nr_chips,void (* fn)(struct s3c_gpio_chip *))396 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
397 				       int nr_chips,
398 				       void (*fn)(struct s3c_gpio_chip *))
399 {
400 	for (; nr_chips > 0; nr_chips--, chips++) {
401 		if (fn)
402 			(fn)(chips);
403 		s3c_gpiolib_add(chips);
404 	}
405 }
406 
s3c64xx_gpiolib_init(void)407 static __init int s3c64xx_gpiolib_init(void)
408 {
409 	s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
410 			    s3c64xx_gpiolib_add_4bit);
411 
412 	s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
413 			    s3c64xx_gpiolib_add_4bit2);
414 
415 	s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
416 
417 	return 0;
418 }
419 
420 core_initcall(s3c64xx_gpiolib_init);
421