Merge branch 'topic/pcsp-fix' into topic/misc
[sfrench/cifs-2.6.git] / arch / arm / mach-ep93xx / gpio.c
1 /*
2  * linux/arch/arm/mach-ep93xx/gpio.c
3  *
4  * Generic EP93xx GPIO handling
5  *
6  * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com>
7  *
8  * Based on code originally from:
9  *  linux/arch/arm/mach-ep93xx/core.c
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 2 as
13  *  published by the Free Software Foundation.
14  */
15
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/seq_file.h>
19 #include <linux/io.h>
20
21 #include <mach/ep93xx-regs.h>
22 #include <asm/gpio.h>
23
24 struct ep93xx_gpio_chip {
25         struct gpio_chip        chip;
26
27         unsigned int            data_reg;
28         unsigned int            data_dir_reg;
29 };
30
31 #define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip)
32
33 /* From core.c */
34 extern void ep93xx_gpio_int_mask(unsigned line);
35 extern void ep93xx_gpio_update_int_params(unsigned port);
36
37 static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
38 {
39         struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
40         unsigned long flags;
41         u8 v;
42
43         local_irq_save(flags);
44         v = __raw_readb(ep93xx_chip->data_dir_reg);
45         v &= ~(1 << offset);
46         __raw_writeb(v, ep93xx_chip->data_dir_reg);
47         local_irq_restore(flags);
48
49         return 0;
50 }
51
52 static int ep93xx_gpio_direction_output(struct gpio_chip *chip,
53                                         unsigned offset, int val)
54 {
55         struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
56         unsigned long flags;
57         int line;
58         u8 v;
59
60         local_irq_save(flags);
61
62         /* Set the value */
63         v = __raw_readb(ep93xx_chip->data_reg);
64         if (val)
65                 v |= (1 << offset);
66         else
67                 v &= ~(1 << offset);
68         __raw_writeb(v, ep93xx_chip->data_reg);
69
70         /* Drive as an output */
71         line = chip->base + offset;
72         if (line <= EP93XX_GPIO_LINE_MAX_IRQ) {
73                 /* Ports A/B/F */
74                 ep93xx_gpio_int_mask(line);
75                 ep93xx_gpio_update_int_params(line >> 3);
76         }
77
78         v = __raw_readb(ep93xx_chip->data_dir_reg);
79         v |= (1 << offset);
80         __raw_writeb(v, ep93xx_chip->data_dir_reg);
81
82         local_irq_restore(flags);
83
84         return 0;
85 }
86
87 static int ep93xx_gpio_get(struct gpio_chip *chip, unsigned offset)
88 {
89         struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
90
91         return !!(__raw_readb(ep93xx_chip->data_reg) & (1 << offset));
92 }
93
94 static void ep93xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
95 {
96         struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
97         unsigned long flags;
98         u8 v;
99
100         local_irq_save(flags);
101         v = __raw_readb(ep93xx_chip->data_reg);
102         if (val)
103                 v |= (1 << offset);
104         else
105                 v &= ~(1 << offset);
106         __raw_writeb(v, ep93xx_chip->data_reg);
107         local_irq_restore(flags);
108 }
109
110 static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
111 {
112         struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
113         u8 data_reg, data_dir_reg;
114         int i;
115
116         data_reg = __raw_readb(ep93xx_chip->data_reg);
117         data_dir_reg = __raw_readb(ep93xx_chip->data_dir_reg);
118
119         for (i = 0; i < chip->ngpio; i++)
120                 seq_printf(s, "GPIO %s%d: %s %s\n", chip->label, i,
121                            (data_reg & (1 << i)) ? "set" : "clear",
122                            (data_dir_reg & (1 << i)) ? "out" : "in");
123 }
124
125 #define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio)                      \
126         {                                                               \
127                 .chip = {                                               \
128                         .label            = name,                       \
129                         .direction_input  = ep93xx_gpio_direction_input, \
130                         .direction_output = ep93xx_gpio_direction_output, \
131                         .get              = ep93xx_gpio_get,            \
132                         .set              = ep93xx_gpio_set,            \
133                         .dbg_show         = ep93xx_gpio_dbg_show,       \
134                         .base             = base_gpio,                  \
135                         .ngpio            = 8,                          \
136                 },                                                      \
137                 .data_reg       = EP93XX_GPIO_REG(dr),                  \
138                 .data_dir_reg   = EP93XX_GPIO_REG(ddr),                 \
139         }
140
141 static struct ep93xx_gpio_chip ep93xx_gpio_banks[] = {
142         EP93XX_GPIO_BANK("A", 0x00, 0x10, 0),
143         EP93XX_GPIO_BANK("B", 0x04, 0x14, 8),
144         EP93XX_GPIO_BANK("C", 0x08, 0x18, 40),
145         EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24),
146         EP93XX_GPIO_BANK("E", 0x20, 0x24, 32),
147         EP93XX_GPIO_BANK("F", 0x30, 0x34, 16),
148         EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48),
149         EP93XX_GPIO_BANK("H", 0x40, 0x44, 56),
150 };
151
152 void __init ep93xx_gpio_init(void)
153 {
154         int i;
155
156         for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++)
157                 gpiochip_add(&ep93xx_gpio_banks[i].chip);
158 }