blob: d41200382208c6fc8918b178e991a2151ae42dd8 [file] [log] [blame]
dmitry pervushin5cccd372009-04-23 12:24:13 +01001/*
2 * Freescale STMP378X/STMP378X Pin Multiplexing
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
dmitry pervushin98f420b2009-05-31 13:32:11 +010018#define DEBUG
dmitry pervushin5cccd372009-04-23 12:24:13 +010019#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/sysdev.h>
23#include <linux/string.h>
24#include <linux/bitops.h>
25#include <linux/sysdev.h>
26#include <linux/irq.h>
27
28#include <mach/hardware.h>
dmitry pervushin98f420b2009-05-31 13:32:11 +010029#include <mach/platform.h>
dmitry pervushin5cccd372009-04-23 12:24:13 +010030#include <mach/regs-pinctrl.h>
31#include <mach/pins.h>
32#include <mach/pinmux.h>
33
34#define NR_BANKS ARRAY_SIZE(pinmux_banks)
35static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
36 [0] = {
37 .hw_muxsel = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010038 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
39 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
dmitry pervushin5cccd372009-04-23 12:24:13 +010040 },
41 .hw_drive = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010042 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
43 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
44 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
45 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
dmitry pervushin5cccd372009-04-23 12:24:13 +010046 },
dmitry pervushin98f420b2009-05-31 13:32:11 +010047 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
dmitry pervushin5cccd372009-04-23 12:24:13 +010048 .functions = { 0x0, 0x1, 0x2, 0x3 },
49 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
50
dmitry pervushin98f420b2009-05-31 13:32:11 +010051 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
52 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
53 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
dmitry pervushin5cccd372009-04-23 12:24:13 +010054 .irq = IRQ_GPIO0,
55
dmitry pervushin98f420b2009-05-31 13:32:11 +010056 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
57 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
58 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
59 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
60 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
dmitry pervushin5cccd372009-04-23 12:24:13 +010061 },
62 [1] = {
63 .hw_muxsel = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010064 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
65 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
dmitry pervushin5cccd372009-04-23 12:24:13 +010066 },
67 .hw_drive = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010068 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
69 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
70 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
71 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
dmitry pervushin5cccd372009-04-23 12:24:13 +010072 },
dmitry pervushin98f420b2009-05-31 13:32:11 +010073 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
dmitry pervushin5cccd372009-04-23 12:24:13 +010074 .functions = { 0x0, 0x1, 0x2, 0x3 },
75 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
76
dmitry pervushin98f420b2009-05-31 13:32:11 +010077 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
78 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
79 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
dmitry pervushin5cccd372009-04-23 12:24:13 +010080 .irq = IRQ_GPIO1,
81
dmitry pervushin98f420b2009-05-31 13:32:11 +010082 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
83 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
84 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
85 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
86 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
dmitry pervushin5cccd372009-04-23 12:24:13 +010087 },
88 [2] = {
89 .hw_muxsel = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010090 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
91 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
dmitry pervushin5cccd372009-04-23 12:24:13 +010092 },
93 .hw_drive = {
dmitry pervushin98f420b2009-05-31 13:32:11 +010094 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
95 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
96 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
97 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
dmitry pervushin5cccd372009-04-23 12:24:13 +010098 },
dmitry pervushin98f420b2009-05-31 13:32:11 +010099 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100100 .functions = { 0x0, 0x1, 0x2, 0x3 },
101 .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
102
dmitry pervushin98f420b2009-05-31 13:32:11 +0100103 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
104 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
105 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100106 .irq = IRQ_GPIO2,
107
dmitry pervushin98f420b2009-05-31 13:32:11 +0100108 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
109 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
110 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
111 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
112 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100113 },
114 [3] = {
115 .hw_muxsel = {
dmitry pervushin98f420b2009-05-31 13:32:11 +0100116 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
117 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100118 },
119 .hw_drive = {
dmitry pervushin98f420b2009-05-31 13:32:11 +0100120 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
121 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
122 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100123 NULL,
124 },
dmitry pervushin98f420b2009-05-31 13:32:11 +0100125 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
dmitry pervushin5cccd372009-04-23 12:24:13 +0100126 .functions = {0x0, 0x1, 0x2, 0x3},
127 .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
128 },
129};
130
131static inline struct stmp3xxx_pinmux_bank *
132stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
133{
134 unsigned b, p;
135
136 b = STMP3XXX_PINID_TO_BANK(id);
137 p = STMP3XXX_PINID_TO_PINNUM(id);
138 BUG_ON(b >= NR_BANKS);
139 if (bank)
140 *bank = b;
141 if (pin)
142 *pin = p;
143 return &pinmux_banks[b];
144}
145
146/* Check if requested pin is owned by caller */
147static int stmp3xxx_check_pin(unsigned id, const char *label)
148{
149 unsigned pin;
150 struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
151
152 if (!test_bit(pin, &pm->pin_map)) {
153 printk(KERN_WARNING
154 "%s: Accessing free pin %x, caller %s\n",
155 __func__, id, label);
156
157 return -EINVAL;
158 }
159
160 if (label && pm->pin_labels[pin] &&
161 strcmp(label, pm->pin_labels[pin])) {
162 printk(KERN_WARNING
163 "%s: Wrong pin owner %x, caller %s owner %s\n",
164 __func__, id, label, pm->pin_labels[pin]);
165
166 return -EINVAL;
167 }
168 return 0;
169}
170
171void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
172 const char *label)
173{
174 struct stmp3xxx_pinmux_bank *pbank;
175 void __iomem *hwdrive;
176 u32 shift, val;
177 u32 bank, pin;
178
179 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
180 pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
181 bank, pin, strength);
182
183 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
184 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
185 val = pbank->strengths[strength];
186 if (val == 0xff) {
187 printk(KERN_WARNING
188 "%s: strength is not supported for bank %d, caller %s",
189 __func__, bank, label);
190 return;
191 }
192
193 if (stmp3xxx_check_pin(id, label))
194 return;
195
196 pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
197 val << shift, hwdrive);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100198 stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
199 stmp3xxx_setl(val << shift, hwdrive);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100200}
201
202void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
203 const char *label)
204{
205 struct stmp3xxx_pinmux_bank *pbank;
206 void __iomem *hwdrive;
207 u32 shift;
208 u32 bank, pin;
209
210 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
211 pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
212 bank, pin, voltage);
213
214 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
215 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
216
217 if (stmp3xxx_check_pin(id, label))
218 return;
219
220 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
221 __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
222 if (voltage == PIN_1_8V)
dmitry pervushin98f420b2009-05-31 13:32:11 +0100223 stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100224 else
dmitry pervushin98f420b2009-05-31 13:32:11 +0100225 stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100226}
227
228void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
229{
230 struct stmp3xxx_pinmux_bank *pbank;
231 void __iomem *hwpull;
232 u32 bank, pin;
233
234 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
235 pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
236 bank, pin, enable);
237
238 hwpull = pbank->hw_pull;
239
240 if (stmp3xxx_check_pin(id, label))
241 return;
242
243 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
244 __func__, 1 << pin, hwpull);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100245 if (enable)
246 stmp3xxx_setl(1 << pin, hwpull);
247 else
248 stmp3xxx_clearl(1 << pin, hwpull);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100249}
250
251int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
252{
253 struct stmp3xxx_pinmux_bank *pbank;
254 u32 bank, pin;
255 int ret = 0;
256
257 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
258 pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
259 bank, pin, fun);
260
261 if (test_bit(pin, &pbank->pin_map)) {
262 printk(KERN_WARNING
263 "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
264 __func__, bank, pin, label, pbank->pin_labels[pin]);
265 return -EBUSY;
266 }
267
268 set_bit(pin, &pbank->pin_map);
269 pbank->pin_labels[pin] = label;
270
271 stmp3xxx_set_pin_type(id, fun);
272
273 return ret;
274}
275
276void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
277{
278 struct stmp3xxx_pinmux_bank *pbank;
279 void __iomem *hwmux;
280 u32 shift, val;
281 u32 bank, pin;
282
283 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
284
285 hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
286 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
287
288 val = pbank->functions[fun];
289 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
290 pr_debug("%s: writing 0x%x to 0x%p register\n",
291 __func__, val << shift, hwmux);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100292 stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
293 stmp3xxx_setl(val << shift, hwmux);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100294}
295
296void stmp3xxx_release_pin(unsigned id, const char *label)
297{
298 struct stmp3xxx_pinmux_bank *pbank;
299 u32 bank, pin;
300
301 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
302 pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
303
304 if (stmp3xxx_check_pin(id, label))
305 return;
306
307 clear_bit(pin, &pbank->pin_map);
308 pbank->pin_labels[pin] = NULL;
309}
310
311int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
312{
313 struct pin_desc *pin;
314 int p;
315 int err = 0;
316
317 /* Allocate and configure pins */
318 for (p = 0; p < pin_group->nr_pins; p++) {
319 pr_debug("%s: #%d\n", __func__, p);
320 pin = &pin_group->pins[p];
321
322 err = stmp3xxx_request_pin(pin->id, pin->fun, label);
323 if (err)
324 goto out_err;
325
326 stmp3xxx_pin_strength(pin->id, pin->strength, label);
327 stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
328 stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
329 }
330
331 return 0;
332
333out_err:
334 /* Release allocated pins in case of error */
335 while (--p >= 0) {
336 pr_debug("%s: releasing #%d\n", __func__, p);
337 stmp3xxx_release_pin(pin_group->pins[p].id, label);
338 }
339 return err;
340}
341EXPORT_SYMBOL(stmp3xxx_request_pin_group);
342
343void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
344{
345 struct pin_desc *pin;
346 int p;
347
348 for (p = 0; p < pin_group->nr_pins; p++) {
349 pin = &pin_group->pins[p];
350 stmp3xxx_release_pin(pin->id, label);
351 }
352}
353EXPORT_SYMBOL(stmp3xxx_release_pin_group);
354
355static int stmp3xxx_irq_to_gpio(int irq,
356 struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
357{
358 struct stmp3xxx_pinmux_bank *pm;
359
360 for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
361 if (pm->virq <= irq && irq < pm->virq + 32) {
362 *bank = pm;
363 *gpio = irq - pm->virq;
364 return 0;
365 }
366 return -ENOENT;
367}
368
369static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
370{
371 struct stmp3xxx_pinmux_bank *pm;
372 unsigned gpio;
373 int l, p;
374
375 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
376 switch (type) {
377 case IRQ_TYPE_EDGE_RISING:
378 l = 0; p = 1; break;
379 case IRQ_TYPE_EDGE_FALLING:
380 l = 0; p = 0; break;
381 case IRQ_TYPE_LEVEL_HIGH:
382 l = 1; p = 1; break;
383 case IRQ_TYPE_LEVEL_LOW:
384 l = 1; p = 0; break;
385 default:
386 pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
387 __func__, type);
388 return -ENXIO;
389 }
dmitry pervushin98f420b2009-05-31 13:32:11 +0100390
391 if (l)
392 stmp3xxx_setl(1 << gpio, pm->irqlevel);
393 else
394 stmp3xxx_clearl(1 << gpio, pm->irqlevel);
395 if (p)
396 stmp3xxx_setl(1 << gpio, pm->irqpolarity);
397 else
398 stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100399 return 0;
400}
401
402static void stmp3xxx_pin_ack_irq(unsigned irq)
403{
404 u32 stat;
405 struct stmp3xxx_pinmux_bank *pm;
406 unsigned gpio;
407
408 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100409 stat = __raw_readl(pm->irqstat) & (1 << gpio);
410 stmp3xxx_clearl(stat, pm->irqstat);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100411}
412
413static void stmp3xxx_pin_mask_irq(unsigned irq)
414{
415 struct stmp3xxx_pinmux_bank *pm;
416 unsigned gpio;
417
418 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100419 stmp3xxx_clearl(1 << gpio, pm->irqen);
420 stmp3xxx_clearl(1 << gpio, pm->pin2irq);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100421}
422
423static void stmp3xxx_pin_unmask_irq(unsigned irq)
424{
425 struct stmp3xxx_pinmux_bank *pm;
426 unsigned gpio;
427
428 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
dmitry pervushin98f420b2009-05-31 13:32:11 +0100429 stmp3xxx_setl(1 << gpio, pm->irqen);
430 stmp3xxx_setl(1 << gpio, pm->pin2irq);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100431}
432
433static inline
434struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
435{
436 return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
437}
438
439static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
440{
441 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
442 return pm->virq + offset;
443}
444
445static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
446{
447 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
448 unsigned v;
449
dmitry pervushin98f420b2009-05-31 13:32:11 +0100450 v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100451 return v ? 1 : 0;
452}
453
454static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
455{
456 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
457
dmitry pervushin98f420b2009-05-31 13:32:11 +0100458 if (v)
459 stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
460 else
461 stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100462}
463
464static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
465{
466 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
467
dmitry pervushin98f420b2009-05-31 13:32:11 +0100468 stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100469 stmp3xxx_gpio_set(chip, offset, v);
470 return 0;
471}
472
473static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
474{
475 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
476
dmitry pervushin98f420b2009-05-31 13:32:11 +0100477 stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
dmitry pervushin5cccd372009-04-23 12:24:13 +0100478 return 0;
479}
480
481static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
482{
483 return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
484}
485
486static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
487{
488 stmp3xxx_release_pin(chip->base + offset, "gpio");
489}
490
491static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
492{
493 struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
494 int gpio_irq = pm->virq;
495 u32 stat = __raw_readl(pm->irqstat);
496
497 while (stat) {
498 if (stat & 1)
499 irq_desc[gpio_irq].handle_irq(gpio_irq,
500 &irq_desc[gpio_irq]);
501 gpio_irq++;
502 stat >>= 1;
503 }
504}
505
506static struct irq_chip gpio_irq_chip = {
507 .ack = stmp3xxx_pin_ack_irq,
508 .mask = stmp3xxx_pin_mask_irq,
509 .unmask = stmp3xxx_pin_unmask_irq,
510 .set_type = stmp3xxx_set_irqtype,
511};
512
513int __init stmp3xxx_pinmux_init(int virtual_irq_start)
514{
515 int b, r = 0;
516 struct stmp3xxx_pinmux_bank *pm;
517 int virq;
518
519 for (b = 0; b < 3; b++) {
520 /* only banks 0,1,2 are allowed to GPIO */
521 pm = pinmux_banks + b;
522 pm->chip.base = 32 * b;
523 pm->chip.ngpio = 32;
524 pm->chip.owner = THIS_MODULE;
525 pm->chip.can_sleep = 1;
526 pm->chip.exported = 1;
527 pm->chip.to_irq = stmp3xxx_gpio_to_irq;
528 pm->chip.direction_input = stmp3xxx_gpio_input;
529 pm->chip.direction_output = stmp3xxx_gpio_output;
530 pm->chip.get = stmp3xxx_gpio_get;
531 pm->chip.set = stmp3xxx_gpio_set;
532 pm->chip.request = stmp3xxx_gpio_request;
533 pm->chip.free = stmp3xxx_gpio_free;
534 pm->virq = virtual_irq_start + b * 32;
535
536 for (virq = pm->virq; virq < pm->virq; virq++) {
537 gpio_irq_chip.mask(virq);
538 set_irq_chip(virq, &gpio_irq_chip);
539 set_irq_handler(virq, handle_level_irq);
540 set_irq_flags(virq, IRQF_VALID);
541 }
542 r = gpiochip_add(&pm->chip);
543 if (r < 0)
544 break;
545 set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
546 set_irq_data(pm->irq, pm);
547 }
548 return r;
549}
550
551MODULE_AUTHOR("Vladislav Buzov");
552MODULE_LICENSE("GPL");