1 /* linux/arch/arm/plat-s3c24xx/gpiolib.c
2  *
3  * Copyright (c) 2008-2010 Simtec Electronics
4  *	http://armlinux.simtec.co.uk/
5  *	Ben Dooks <ben@simtec.co.uk>
6  *
7  * S3C24XX GPIOlib support
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License.
12 */
13 
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/interrupt.h>
18 #include <linux/sysdev.h>
19 #include <linux/ioport.h>
20 #include <linux/io.h>
21 #include <linux/gpio.h>
22 
23 #include <plat/gpio-core.h>
24 #include <plat/gpio-cfg.h>
25 #include <plat/gpio-cfg-helpers.h>
26 #include <mach/hardware.h>
27 #include <asm/irq.h>
28 #include <plat/pm.h>
29 
30 #include <mach/regs-gpio.h>
31 
s3c24xx_gpiolib_banka_input(struct gpio_chip * chip,unsigned offset)32 static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
33 {
34 	return -EINVAL;
35 }
36 
s3c24xx_gpiolib_banka_output(struct gpio_chip * chip,unsigned offset,int value)37 static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
38 					unsigned offset, int value)
39 {
40 	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
41 	void __iomem *base = ourchip->base;
42 	unsigned long flags;
43 	unsigned long dat;
44 	unsigned long con;
45 
46 	local_irq_save(flags);
47 
48 	con = __raw_readl(base + 0x00);
49 	dat = __raw_readl(base + 0x04);
50 
51 	dat &= ~(1 << offset);
52 	if (value)
53 		dat |= 1 << offset;
54 
55 	__raw_writel(dat, base + 0x04);
56 
57 	con &= ~(1 << offset);
58 
59 	__raw_writel(con, base + 0x00);
60 	__raw_writel(dat, base + 0x04);
61 
62 	local_irq_restore(flags);
63 	return 0;
64 }
65 
s3c24xx_gpiolib_bankf_toirq(struct gpio_chip * chip,unsigned offset)66 static int s3c24xx_gpiolib_bankf_toirq(struct gpio_chip *chip, unsigned offset)
67 {
68 	if (offset < 4)
69 		return IRQ_EINT0 + offset;
70 
71 	if (offset < 8)
72 		return IRQ_EINT4 + offset - 4;
73 
74 	return -EINVAL;
75 }
76 
77 static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = {
78 	.set_config	= s3c_gpio_setcfg_s3c24xx_a,
79 	.get_config	= s3c_gpio_getcfg_s3c24xx_a,
80 };
81 
82 struct s3c_gpio_cfg s3c24xx_gpiocfg_default = {
83 	.set_config	= s3c_gpio_setcfg_s3c24xx,
84 	.get_config	= s3c_gpio_getcfg_s3c24xx,
85 };
86 
87 struct s3c_gpio_chip s3c24xx_gpios[] = {
88 	[0] = {
89 		.base	= S3C2410_GPACON,
90 		.pm	= __gpio_pm(&s3c_gpio_pm_1bit),
91 		.config	= &s3c24xx_gpiocfg_banka,
92 		.chip	= {
93 			.base			= S3C2410_GPA(0),
94 			.owner			= THIS_MODULE,
95 			.label			= "GPIOA",
96 			.ngpio			= 24,
97 			.direction_input	= s3c24xx_gpiolib_banka_input,
98 			.direction_output	= s3c24xx_gpiolib_banka_output,
99 		},
100 	},
101 	[1] = {
102 		.base	= S3C2410_GPBCON,
103 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
104 		.chip	= {
105 			.base			= S3C2410_GPB(0),
106 			.owner			= THIS_MODULE,
107 			.label			= "GPIOB",
108 			.ngpio			= 16,
109 		},
110 	},
111 	[2] = {
112 		.base	= S3C2410_GPCCON,
113 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
114 		.chip	= {
115 			.base			= S3C2410_GPC(0),
116 			.owner			= THIS_MODULE,
117 			.label			= "GPIOC",
118 			.ngpio			= 16,
119 		},
120 	},
121 	[3] = {
122 		.base	= S3C2410_GPDCON,
123 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
124 		.chip	= {
125 			.base			= S3C2410_GPD(0),
126 			.owner			= THIS_MODULE,
127 			.label			= "GPIOD",
128 			.ngpio			= 16,
129 		},
130 	},
131 	[4] = {
132 		.base	= S3C2410_GPECON,
133 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
134 		.chip	= {
135 			.base			= S3C2410_GPE(0),
136 			.label			= "GPIOE",
137 			.owner			= THIS_MODULE,
138 			.ngpio			= 16,
139 		},
140 	},
141 	[5] = {
142 		.base	= S3C2410_GPFCON,
143 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
144 		.chip	= {
145 			.base			= S3C2410_GPF(0),
146 			.owner			= THIS_MODULE,
147 			.label			= "GPIOF",
148 			.ngpio			= 8,
149 			.to_irq			= s3c24xx_gpiolib_bankf_toirq,
150 		},
151 	},
152 	[6] = {
153 		.base	= S3C2410_GPGCON,
154 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
155 		.irq_base = IRQ_EINT8,
156 		.chip	= {
157 			.base			= S3C2410_GPG(0),
158 			.owner			= THIS_MODULE,
159 			.label			= "GPIOG",
160 			.ngpio			= 16,
161 			.to_irq			= samsung_gpiolib_to_irq,
162 		},
163 	}, {
164 		.base	= S3C2410_GPHCON,
165 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
166 		.chip	= {
167 			.base			= S3C2410_GPH(0),
168 			.owner			= THIS_MODULE,
169 			.label			= "GPIOH",
170 			.ngpio			= 11,
171 		},
172 	},
173 		/* GPIOS for the S3C2443 and later devices. */
174 	{
175 		.base	= S3C2440_GPJCON,
176 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
177 		.chip	= {
178 			.base			= S3C2410_GPJ(0),
179 			.owner			= THIS_MODULE,
180 			.label			= "GPIOJ",
181 			.ngpio			= 16,
182 		},
183 	}, {
184 		.base	= S3C2443_GPKCON,
185 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
186 		.chip	= {
187 			.base			= S3C2410_GPK(0),
188 			.owner			= THIS_MODULE,
189 			.label			= "GPIOK",
190 			.ngpio			= 16,
191 		},
192 	}, {
193 		.base	= S3C2443_GPLCON,
194 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
195 		.chip	= {
196 			.base			= S3C2410_GPL(0),
197 			.owner			= THIS_MODULE,
198 			.label			= "GPIOL",
199 			.ngpio			= 15,
200 		},
201 	}, {
202 		.base	= S3C2443_GPMCON,
203 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
204 		.chip	= {
205 			.base			= S3C2410_GPM(0),
206 			.owner			= THIS_MODULE,
207 			.label			= "GPIOM",
208 			.ngpio			= 2,
209 		},
210 	},
211 };
212 
213 
s3c24xx_gpiolib_init(void)214 static __init int s3c24xx_gpiolib_init(void)
215 {
216 	struct s3c_gpio_chip *chip = s3c24xx_gpios;
217 	int gpn;
218 
219 	for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++) {
220 		if (!chip->config)
221 			chip->config = &s3c24xx_gpiocfg_default;
222 
223 		s3c_gpiolib_add(chip);
224 	}
225 
226 	return 0;
227 }
228 
229 core_initcall(s3c24xx_gpiolib_init);
230