]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - arch/arm/plat-s3c64xx/gpiolib.c
28ba23502bce4e7cb00710435d373de4928782c0
[mirror_ubuntu-bionic-kernel.git] / arch / arm / plat-s3c64xx / gpiolib.c
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
22 #include <plat/gpio-core.h>
23 #include <plat/regs-gpio.h>
24
25 /* GPIO bank summary:
26 *
27 * Bank GPIOs Style SlpCon ExtInt Group
28 * A 8 4Bit Yes 1
29 * B 7 4Bit Yes 1
30 * C 8 4Bit Yes 2
31 * D 5 4Bit Yes 3
32 * E 5 4Bit Yes None
33 * F 16 2Bit Yes 4 [1]
34 * G 7 4Bit Yes 5
35 * H 10 4Bit[2] Yes 6
36 * I 16 2Bit Yes None
37 * J 12 2Bit Yes None
38 * K 16 4Bit[2] No None
39 * L 15 4Bit[2] No None
40 * M 6 4Bit No IRQ_EINT
41 * N 16 2Bit No IRQ_EINT
42 * O 16 2Bit Yes 7
43 * P 15 2Bit Yes 8
44 * Q 9 2Bit Yes 9
45 *
46 * [1] BANKF pins 14,15 do not form part of the external interrupt sources
47 * [2] BANK has two control registers, GPxCON0 and GPxCON1
48 */
49
50 #define OFF_GPCON (0x00)
51 #define OFF_GPDAT (0x04)
52
53 #define con_4bit_shift(__off) ((__off) * 4)
54
55 /* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
56 * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
57 * following example:
58 *
59 * base + 0x00: Control register, 4 bits per gpio
60 * gpio n: 4 bits starting at (4*n)
61 * 0000 = input, 0001 = output, others mean special-function
62 * base + 0x04: Data register, 1 bit per gpio
63 * bit n: data bit n
64 *
65 * Note, since the data register is one bit per gpio and is at base + 0x4
66 * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
67 * the output.
68 */
69
70 static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
71 {
72 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
73 void __iomem *base = ourchip->base;
74 unsigned long con;
75
76 con = __raw_readl(base + OFF_GPCON);
77 con &= ~(0xf << con_4bit_shift(offset));
78 __raw_writel(con, base + OFF_GPCON);
79
80 return 0;
81 }
82
83 static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
84 unsigned offset, int value)
85 {
86 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
87 void __iomem *base = ourchip->base;
88 unsigned long con;
89 unsigned long dat;
90
91 con = __raw_readl(base + OFF_GPCON);
92 con &= ~(0xf << con_4bit_shift(offset));
93 con |= 0x1 << con_4bit_shift(offset);
94
95 dat = __raw_readl(base + OFF_GPDAT);
96 if (value)
97 dat |= 1 << offset;
98 else
99 dat &= ~(1 << offset);
100
101 __raw_writel(dat, base + OFF_GPDAT);
102 __raw_writel(con, base + OFF_GPCON);
103 __raw_writel(dat, base + OFF_GPDAT);
104
105 return 0;
106 }
107
108 /* The next set of routines are for the case where the GPIO configuration
109 * registers are 4 bits per GPIO but there is more than one register (the
110 * bank has more than 8 GPIOs.
111 *
112 * This case is the similar to the 4 bit case, but the registers are as
113 * follows:
114 *
115 * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
116 * gpio n: 4 bits starting at (4*n)
117 * 0000 = input, 0001 = output, others mean special-function
118 * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
119 * gpio n: 4 bits starting at (4*n)
120 * 0000 = input, 0001 = output, others mean special-function
121 * base + 0x08: Data register, 1 bit per gpio
122 * bit n: data bit n
123 *
124 * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
125 * store the 'base + 0x4' address so that these routines see the data
126 * register at ourchip->base + 0x04.
127 */
128
129 static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
130 {
131 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
132 void __iomem *base = ourchip->base;
133 void __iomem *regcon = base;
134 unsigned long con;
135
136 if (offset > 7)
137 offset -= 8;
138 else
139 regcon -= 4;
140
141 con = __raw_readl(regcon);
142 con &= ~(0xf << con_4bit_shift(offset));
143 __raw_writel(con, regcon);
144
145 return 0;
146
147 }
148
149 static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
150 unsigned offset, int value)
151 {
152 struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
153 void __iomem *base = ourchip->base;
154 void __iomem *regcon = base;
155 unsigned long con;
156 unsigned long dat;
157
158 if (offset > 7)
159 offset -= 8;
160 else
161 regcon -= 4;
162
163 con = __raw_readl(regcon);
164 con &= ~(0xf << con_4bit_shift(offset));
165 con |= 0x1 << con_4bit_shift(offset);
166
167 dat = __raw_readl(base + OFF_GPDAT);
168 if (value)
169 dat |= 1 << offset;
170 else
171 dat &= ~(1 << offset);
172
173 __raw_writel(dat, base + OFF_GPDAT);
174 __raw_writel(con, regcon);
175 __raw_writel(dat, base + OFF_GPDAT);
176
177 return 0;
178 }
179
180 static struct s3c_gpio_chip gpio_4bit[] = {
181 {
182 .base = S3C64XX_GPA_BASE,
183 .chip = {
184 .base = S3C64XX_GPA(0),
185 .ngpio = S3C64XX_GPIO_A_NR,
186 .label = "GPA",
187 },
188 }, {
189 .base = S3C64XX_GPB_BASE,
190 .chip = {
191 .base = S3C64XX_GPB(0),
192 .ngpio = S3C64XX_GPIO_B_NR,
193 .label = "GPB",
194 },
195 }, {
196 .base = S3C64XX_GPC_BASE,
197 .chip = {
198 .base = S3C64XX_GPC(0),
199 .ngpio = S3C64XX_GPIO_C_NR,
200 .label = "GPC",
201 },
202 }, {
203 .base = S3C64XX_GPD_BASE,
204 .chip = {
205 .base = S3C64XX_GPD(0),
206 .ngpio = S3C64XX_GPIO_D_NR,
207 .label = "GPD",
208 },
209 }, {
210 .base = S3C64XX_GPE_BASE,
211 .chip = {
212 .base = S3C64XX_GPE(0),
213 .ngpio = S3C64XX_GPIO_E_NR,
214 .label = "GPE",
215 },
216 }, {
217 .base = S3C64XX_GPG_BASE,
218 .chip = {
219 .base = S3C64XX_GPG(0),
220 .ngpio = S3C64XX_GPIO_G_NR,
221 .label = "GPG",
222 },
223 }, {
224 .base = S3C64XX_GPM_BASE,
225 .chip = {
226 .base = S3C64XX_GPM(0),
227 .ngpio = S3C64XX_GPIO_M_NR,
228 .label = "GPM",
229 },
230 },
231 };
232
233 static struct s3c_gpio_chip gpio_4bit2[] = {
234 {
235 .base = S3C64XX_GPH_BASE + 0x4,
236 .chip = {
237 .base = S3C64XX_GPH(0),
238 .ngpio = S3C64XX_GPIO_H_NR,
239 .label = "GPH",
240 },
241 }, {
242 .base = S3C64XX_GPK_BASE + 0x4,
243 .chip = {
244 .base = S3C64XX_GPK(0),
245 .ngpio = S3C64XX_GPIO_K_NR,
246 .label = "GPK",
247 },
248 }, {
249 .base = S3C64XX_GPL_BASE + 0x4,
250 .chip = {
251 .base = S3C64XX_GPL(0),
252 .ngpio = S3C64XX_GPIO_L_NR,
253 .label = "GPL",
254 },
255 },
256 };
257
258 static struct s3c_gpio_chip gpio_2bit[] = {
259 {
260 .base = S3C64XX_GPF_BASE,
261 .chip = {
262 .base = S3C64XX_GPF(0),
263 .ngpio = S3C64XX_GPIO_F_NR,
264 .label = "GPF",
265 },
266 }, {
267 .base = S3C64XX_GPI_BASE,
268 .chip = {
269 .base = S3C64XX_GPI(0),
270 .ngpio = S3C64XX_GPIO_I_NR,
271 .label = "GPI",
272 },
273 }, {
274 .base = S3C64XX_GPJ_BASE,
275 .chip = {
276 .base = S3C64XX_GPJ(0),
277 .ngpio = S3C64XX_GPIO_J_NR,
278 .label = "GPJ",
279 },
280 }, {
281 .base = S3C64XX_GPN_BASE,
282 .chip = {
283 .base = S3C64XX_GPN(0),
284 .ngpio = S3C64XX_GPIO_N_NR,
285 .label = "GPN",
286 },
287 }, {
288 .base = S3C64XX_GPO_BASE,
289 .chip = {
290 .base = S3C64XX_GPO(0),
291 .ngpio = S3C64XX_GPIO_O_NR,
292 .label = "GPO",
293 },
294 }, {
295 .base = S3C64XX_GPP_BASE,
296 .chip = {
297 .base = S3C64XX_GPP(0),
298 .ngpio = S3C64XX_GPIO_P_NR,
299 .label = "GPP",
300 },
301 }, {
302 .base = S3C64XX_GPQ_BASE,
303 .chip = {
304 .base = S3C64XX_GPQ(0),
305 .ngpio = S3C64XX_GPIO_Q_NR,
306 .label = "GPQ",
307 },
308 },
309 };
310
311 static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
312 {
313 chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
314 chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
315 }
316
317 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
318 {
319 chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
320 chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
321 }
322
323 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
324 int nr_chips,
325 void (*fn)(struct s3c_gpio_chip *))
326 {
327 for (; nr_chips > 0; nr_chips--, chips++) {
328 if (fn)
329 (fn)(chips);
330 s3c_gpiolib_add(chips);
331 }
332 }
333
334 static __init int s3c64xx_gpiolib_init(void)
335 {
336 s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
337 s3c64xx_gpiolib_add_4bit);
338
339 s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
340 s3c64xx_gpiolib_add_4bit2);
341
342 s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
343
344 return 0;
345 }
346
347 arch_initcall(s3c64xx_gpiolib_init);