• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* linux/arch/arm/mach-s5p64x0/gpiolib.c
2  *
3  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
4  *		http://www.samsung.com
5  *
6  * S5P64X0 - 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 <linux/gpio.h>
17 
18 #include <mach/map.h>
19 #include <mach/regs-gpio.h>
20 #include <mach/regs-clock.h>
21 
22 #include <plat/cpu.h>
23 #include <plat/gpio-core.h>
24 #include <plat/gpio-cfg.h>
25 #include <plat/gpio-cfg-helpers.h>
26 
27 /*
28  * S5P6440 GPIO bank summary:
29  *
30  * Bank	GPIOs	Style	SlpCon	ExtInt Group
31  * A	6	4Bit	Yes	1
32  * B	7	4Bit	Yes	1
33  * C	8	4Bit	Yes	2
34  * F	2	2Bit	Yes	4 [1]
35  * G	7	4Bit	Yes	5
36  * H	10	4Bit[2]	Yes	6
37  * I	16	2Bit	Yes	None
38  * J	12	2Bit	Yes	None
39  * N	16	2Bit	No	IRQ_EINT
40  * P	8	2Bit	Yes	8
41  * R	15	4Bit[2]	Yes	8
42  *
43  * S5P6450 GPIO bank summary:
44  *
45  * Bank	GPIOs	Style	SlpCon	ExtInt Group
46  * A	6	4Bit	Yes	1
47  * B	7	4Bit	Yes	1
48  * C	8	4Bit	Yes	2
49  * D	8	4Bit	Yes	None
50  * F	2	2Bit	Yes	None
51  * G	14	4Bit[2]	Yes	5
52  * H	10	4Bit[2]	Yes	6
53  * I	16	2Bit	Yes	None
54  * J	12	2Bit	Yes	None
55  * K	5	4Bit	Yes	None
56  * N	16	2Bit	No	IRQ_EINT
57  * P	11	2Bit	Yes	8
58  * Q	14	2Bit	Yes	None
59  * R	15	4Bit[2]	Yes	None
60  * S	8	2Bit	Yes	None
61  *
62  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
63  * [2] BANK has two control registers, GPxCON0 and GPxCON1
64  */
65 
s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip * chip,unsigned int offset)66 static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
67 					     unsigned int offset)
68 {
69 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
70 	void __iomem *base = ourchip->base;
71 	void __iomem *regcon = base;
72 	unsigned long con;
73 	unsigned long flags;
74 
75 	switch (offset) {
76 	case 6:
77 		offset += 1;
78 	case 0:
79 	case 1:
80 	case 2:
81 	case 3:
82 	case 4:
83 	case 5:
84 		regcon -= 4;
85 		break;
86 	default:
87 		offset -= 7;
88 		break;
89 	}
90 
91 	s3c_gpio_lock(ourchip, flags);
92 
93 	con = __raw_readl(regcon);
94 	con &= ~(0xf << con_4bit_shift(offset));
95 	__raw_writel(con, regcon);
96 
97 	s3c_gpio_unlock(ourchip, flags);
98 
99 	return 0;
100 }
101 
s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip * chip,unsigned int offset,int value)102 static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
103 					      unsigned int offset, int value)
104 {
105 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
106 	void __iomem *base = ourchip->base;
107 	void __iomem *regcon = base;
108 	unsigned long con;
109 	unsigned long dat;
110 	unsigned long flags;
111 	unsigned con_offset  = offset;
112 
113 	switch (con_offset) {
114 	case 6:
115 		con_offset += 1;
116 	case 0:
117 	case 1:
118 	case 2:
119 	case 3:
120 	case 4:
121 	case 5:
122 		regcon -= 4;
123 		break;
124 	default:
125 		con_offset -= 7;
126 		break;
127 	}
128 
129 	s3c_gpio_lock(ourchip, flags);
130 
131 	con = __raw_readl(regcon);
132 	con &= ~(0xf << con_4bit_shift(con_offset));
133 	con |= 0x1 << con_4bit_shift(con_offset);
134 
135 	dat = __raw_readl(base + GPIODAT_OFF);
136 	if (value)
137 		dat |= 1 << offset;
138 	else
139 		dat &= ~(1 << offset);
140 
141 	__raw_writel(con, regcon);
142 	__raw_writel(dat, base + GPIODAT_OFF);
143 
144 	s3c_gpio_unlock(ourchip, flags);
145 
146 	return 0;
147 }
148 
s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip * chip,unsigned int off,unsigned int cfg)149 int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
150 				   unsigned int off, unsigned int cfg)
151 {
152 	void __iomem *reg = chip->base;
153 	unsigned int shift;
154 	u32 con;
155 
156 	switch (off) {
157 	case 0:
158 	case 1:
159 	case 2:
160 	case 3:
161 	case 4:
162 	case 5:
163 		shift = (off & 7) * 4;
164 		reg -= 4;
165 		break;
166 	case 6:
167 		shift = ((off + 1) & 7) * 4;
168 		reg -= 4;
169 	default:
170 		shift = ((off + 1) & 7) * 4;
171 		break;
172 	}
173 
174 	if (s3c_gpio_is_cfg_special(cfg)) {
175 		cfg &= 0xf;
176 		cfg <<= shift;
177 	}
178 
179 	con = __raw_readl(reg);
180 	con &= ~(0xf << shift);
181 	con |= cfg;
182 	__raw_writel(con, reg);
183 
184 	return 0;
185 }
186 
187 static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
188 	{
189 		.cfg_eint	= 0,
190 	}, {
191 		.cfg_eint	= 7,
192 	}, {
193 		.cfg_eint	= 3,
194 		.set_config	= s5p64x0_gpio_setcfg_4bit_rbank,
195 	}, {
196 		.cfg_eint	= 0,
197 		.set_config	= s3c_gpio_setcfg_s3c24xx,
198 		.get_config	= s3c_gpio_getcfg_s3c24xx,
199 	}, {
200 		.cfg_eint	= 2,
201 		.set_config	= s3c_gpio_setcfg_s3c24xx,
202 		.get_config	= s3c_gpio_getcfg_s3c24xx,
203 	}, {
204 		.cfg_eint	= 3,
205 		.set_config	= s3c_gpio_setcfg_s3c24xx,
206 		.get_config	= s3c_gpio_getcfg_s3c24xx,
207 	},
208 };
209 
210 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
211 	{
212 		.base	= S5P64X0_GPA_BASE,
213 		.config	= &s5p64x0_gpio_cfgs[1],
214 		.chip	= {
215 			.base	= S5P6440_GPA(0),
216 			.ngpio	= S5P6440_GPIO_A_NR,
217 			.label	= "GPA",
218 		},
219 	}, {
220 		.base	= S5P64X0_GPB_BASE,
221 		.config	= &s5p64x0_gpio_cfgs[1],
222 		.chip	= {
223 			.base	= S5P6440_GPB(0),
224 			.ngpio	= S5P6440_GPIO_B_NR,
225 			.label	= "GPB",
226 		},
227 	}, {
228 		.base	= S5P64X0_GPC_BASE,
229 		.config	= &s5p64x0_gpio_cfgs[1],
230 		.chip	= {
231 			.base	= S5P6440_GPC(0),
232 			.ngpio	= S5P6440_GPIO_C_NR,
233 			.label	= "GPC",
234 		},
235 	}, {
236 		.base	= S5P64X0_GPG_BASE,
237 		.config	= &s5p64x0_gpio_cfgs[1],
238 		.chip	= {
239 			.base	= S5P6440_GPG(0),
240 			.ngpio	= S5P6440_GPIO_G_NR,
241 			.label	= "GPG",
242 		},
243 	},
244 };
245 
246 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
247 	{
248 		.base	= S5P64X0_GPH_BASE + 0x4,
249 		.config	= &s5p64x0_gpio_cfgs[1],
250 		.chip	= {
251 			.base	= S5P6440_GPH(0),
252 			.ngpio	= S5P6440_GPIO_H_NR,
253 			.label	= "GPH",
254 		},
255 	},
256 };
257 
258 static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
259 	{
260 		.base	= S5P64X0_GPR_BASE + 0x4,
261 		.config	= &s5p64x0_gpio_cfgs[2],
262 		.chip	= {
263 			.base	= S5P6440_GPR(0),
264 			.ngpio	= S5P6440_GPIO_R_NR,
265 			.label	= "GPR",
266 		},
267 	},
268 };
269 
270 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
271 	{
272 		.base	= S5P64X0_GPF_BASE,
273 		.config	= &s5p64x0_gpio_cfgs[5],
274 		.chip	= {
275 			.base	= S5P6440_GPF(0),
276 			.ngpio	= S5P6440_GPIO_F_NR,
277 			.label	= "GPF",
278 		},
279 	}, {
280 		.base	= S5P64X0_GPI_BASE,
281 		.config	= &s5p64x0_gpio_cfgs[3],
282 		.chip	= {
283 			.base	= S5P6440_GPI(0),
284 			.ngpio	= S5P6440_GPIO_I_NR,
285 			.label	= "GPI",
286 		},
287 	}, {
288 		.base	= S5P64X0_GPJ_BASE,
289 		.config	= &s5p64x0_gpio_cfgs[3],
290 		.chip	= {
291 			.base	= S5P6440_GPJ(0),
292 			.ngpio	= S5P6440_GPIO_J_NR,
293 			.label	= "GPJ",
294 		},
295 	}, {
296 		.base	= S5P64X0_GPN_BASE,
297 		.config	= &s5p64x0_gpio_cfgs[4],
298 		.chip	= {
299 			.base	= S5P6440_GPN(0),
300 			.ngpio	= S5P6440_GPIO_N_NR,
301 			.label	= "GPN",
302 		},
303 	}, {
304 		.base	= S5P64X0_GPP_BASE,
305 		.config	= &s5p64x0_gpio_cfgs[5],
306 		.chip	= {
307 			.base	= S5P6440_GPP(0),
308 			.ngpio	= S5P6440_GPIO_P_NR,
309 			.label	= "GPP",
310 		},
311 	},
312 };
313 
314 static struct s3c_gpio_chip s5p6450_gpio_4bit[] = {
315 	{
316 		.base	= S5P64X0_GPA_BASE,
317 		.config	= &s5p64x0_gpio_cfgs[1],
318 		.chip	= {
319 			.base	= S5P6450_GPA(0),
320 			.ngpio	= S5P6450_GPIO_A_NR,
321 			.label	= "GPA",
322 		},
323 	}, {
324 		.base	= S5P64X0_GPB_BASE,
325 		.config	= &s5p64x0_gpio_cfgs[1],
326 		.chip	= {
327 			.base	= S5P6450_GPB(0),
328 			.ngpio	= S5P6450_GPIO_B_NR,
329 			.label	= "GPB",
330 		},
331 	}, {
332 		.base	= S5P64X0_GPC_BASE,
333 		.config	= &s5p64x0_gpio_cfgs[1],
334 		.chip	= {
335 			.base	= S5P6450_GPC(0),
336 			.ngpio	= S5P6450_GPIO_C_NR,
337 			.label	= "GPC",
338 		},
339 	}, {
340 		.base	= S5P6450_GPD_BASE,
341 		.config	= &s5p64x0_gpio_cfgs[1],
342 		.chip	= {
343 			.base	= S5P6450_GPD(0),
344 			.ngpio	= S5P6450_GPIO_D_NR,
345 			.label	= "GPD",
346 		},
347 	}, {
348 		.base	= S5P6450_GPK_BASE,
349 		.config	= &s5p64x0_gpio_cfgs[1],
350 		.chip	= {
351 			.base	= S5P6450_GPK(0),
352 			.ngpio	= S5P6450_GPIO_K_NR,
353 			.label	= "GPK",
354 		},
355 	},
356 };
357 
358 static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = {
359 	{
360 		.base	= S5P64X0_GPG_BASE + 0x4,
361 		.config	= &s5p64x0_gpio_cfgs[1],
362 		.chip	= {
363 			.base	= S5P6450_GPG(0),
364 			.ngpio	= S5P6450_GPIO_G_NR,
365 			.label	= "GPG",
366 		},
367 	}, {
368 		.base	= S5P64X0_GPH_BASE + 0x4,
369 		.config	= &s5p64x0_gpio_cfgs[1],
370 		.chip	= {
371 			.base	= S5P6450_GPH(0),
372 			.ngpio	= S5P6450_GPIO_H_NR,
373 			.label	= "GPH",
374 		},
375 	},
376 };
377 
378 static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = {
379 	{
380 		.base	= S5P64X0_GPR_BASE + 0x4,
381 		.config	= &s5p64x0_gpio_cfgs[2],
382 		.chip	= {
383 			.base	= S5P6450_GPR(0),
384 			.ngpio	= S5P6450_GPIO_R_NR,
385 			.label	= "GPR",
386 		},
387 	},
388 };
389 
390 static struct s3c_gpio_chip s5p6450_gpio_2bit[] = {
391 	{
392 		.base	= S5P64X0_GPF_BASE,
393 		.config	= &s5p64x0_gpio_cfgs[5],
394 		.chip	= {
395 			.base	= S5P6450_GPF(0),
396 			.ngpio	= S5P6450_GPIO_F_NR,
397 			.label	= "GPF",
398 		},
399 	}, {
400 		.base	= S5P64X0_GPI_BASE,
401 		.config	= &s5p64x0_gpio_cfgs[3],
402 		.chip	= {
403 			.base	= S5P6450_GPI(0),
404 			.ngpio	= S5P6450_GPIO_I_NR,
405 			.label	= "GPI",
406 		},
407 	}, {
408 		.base	= S5P64X0_GPJ_BASE,
409 		.config	= &s5p64x0_gpio_cfgs[3],
410 		.chip	= {
411 			.base	= S5P6450_GPJ(0),
412 			.ngpio	= S5P6450_GPIO_J_NR,
413 			.label	= "GPJ",
414 		},
415 	}, {
416 		.base	= S5P64X0_GPN_BASE,
417 		.config	= &s5p64x0_gpio_cfgs[4],
418 		.chip	= {
419 			.base	= S5P6450_GPN(0),
420 			.ngpio	= S5P6450_GPIO_N_NR,
421 			.label	= "GPN",
422 		},
423 	}, {
424 		.base	= S5P64X0_GPP_BASE,
425 		.config	= &s5p64x0_gpio_cfgs[5],
426 		.chip	= {
427 			.base	= S5P6450_GPP(0),
428 			.ngpio	= S5P6450_GPIO_P_NR,
429 			.label	= "GPP",
430 		},
431 	}, {
432 		.base	= S5P6450_GPQ_BASE,
433 		.config	= &s5p64x0_gpio_cfgs[4],
434 		.chip	= {
435 			.base	= S5P6450_GPQ(0),
436 			.ngpio	= S5P6450_GPIO_Q_NR,
437 			.label	= "GPQ",
438 		},
439 	}, {
440 		.base	= S5P6450_GPS_BASE,
441 		.config	= &s5p64x0_gpio_cfgs[5],
442 		.chip	= {
443 			.base	= S5P6450_GPS(0),
444 			.ngpio	= S5P6450_GPIO_S_NR,
445 			.label	= "GPS",
446 		},
447 	},
448 };
449 
s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg * chipcfg,int nr_chips)450 void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
451 {
452 	for (; nr_chips > 0; nr_chips--, chipcfg++) {
453 		if (!chipcfg->set_config)
454 			chipcfg->set_config	= s3c_gpio_setcfg_s3c64xx_4bit;
455 		if (!chipcfg->get_config)
456 			chipcfg->get_config	= s3c_gpio_getcfg_s3c64xx_4bit;
457 		if (!chipcfg->set_pull)
458 			chipcfg->set_pull	= s3c_gpio_setpull_updown;
459 		if (!chipcfg->get_pull)
460 			chipcfg->get_pull	= s3c_gpio_getpull_updown;
461 	}
462 }
463 
s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip * chip,int nr_chips)464 static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
465 						int nr_chips)
466 {
467 	for (; nr_chips > 0; nr_chips--, chip++) {
468 		chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
469 		chip->chip.direction_output =
470 					s5p64x0_gpiolib_rbank_4bit2_output;
471 		s3c_gpiolib_add(chip);
472 	}
473 }
474 
s5p64x0_gpiolib_init(void)475 static int __init s5p64x0_gpiolib_init(void)
476 {
477 	s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
478 				ARRAY_SIZE(s5p64x0_gpio_cfgs));
479 
480 	if (soc_is_s5p6450()) {
481 		samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit,
482 					ARRAY_SIZE(s5p6450_gpio_2bit));
483 
484 		samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit,
485 					ARRAY_SIZE(s5p6450_gpio_4bit));
486 
487 		samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2,
488 					ARRAY_SIZE(s5p6450_gpio_4bit2));
489 
490 		s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2,
491 					ARRAY_SIZE(s5p6450_gpio_rbank_4bit2));
492 	} else {
493 		samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit,
494 					ARRAY_SIZE(s5p6440_gpio_2bit));
495 
496 		samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
497 					ARRAY_SIZE(s5p6440_gpio_4bit));
498 
499 		samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
500 					ARRAY_SIZE(s5p6440_gpio_4bit2));
501 
502 		s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
503 					ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
504 	}
505 
506 	return 0;
507 }
508 core_initcall(s5p64x0_gpiolib_init);
509