|
1 | 1 | /* |
2 | | - * Copyright (C) 2007, OpenWrt.org, Florian Fainelli <[email protected]> |
| 2 | + * Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <[email protected]> |
3 | 3 | * Architecture specific GPIO support |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify it |
|
27 | 27 | * others have a second one : GPIO2 |
28 | 28 | */ |
29 | 29 |
|
| 30 | +#include <linux/kernel.h> |
30 | 31 | #include <linux/module.h> |
| 32 | +#include <linux/types.h> |
| 33 | +#include <linux/platform_device.h> |
| 34 | +#include <linux/gpio.h> |
31 | 35 |
|
32 | 36 | #include <asm/mach-au1x00/au1000.h> |
33 | 37 | #include <asm/gpio.h> |
34 | 38 |
|
35 | | -#define gpio1 sys |
36 | | -#if !defined(CONFIG_SOC_AU1000) |
37 | | - |
38 | | -static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE; |
39 | | -#define GPIO2_OUTPUT_ENABLE_MASK 0x00010000 |
| 39 | +struct au1000_gpio_chip { |
| 40 | + struct gpio_chip chip; |
| 41 | + void __iomem *regbase; |
| 42 | +}; |
40 | 43 |
|
41 | | -static int au1xxx_gpio2_read(unsigned gpio) |
| 44 | +#if !defined(CONFIG_SOC_AU1000) |
| 45 | +static int au1000_gpio2_get(struct gpio_chip *chip, unsigned offset) |
42 | 46 | { |
43 | | - gpio -= AU1XXX_GPIO_BASE; |
44 | | - return ((gpio2->pinstate >> gpio) & 0x01); |
| 47 | + u32 mask = 1 << offset; |
| 48 | + struct au1000_gpio_chip *gpch; |
| 49 | + |
| 50 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 51 | + return readl(gpch->regbase + AU1000_GPIO2_ST) & mask; |
45 | 52 | } |
46 | 53 |
|
47 | | -static void au1xxx_gpio2_write(unsigned gpio, int value) |
| 54 | +static void au1000_gpio2_set(struct gpio_chip *chip, |
| 55 | + unsigned offset, int value) |
48 | 56 | { |
49 | | - gpio -= AU1XXX_GPIO_BASE; |
| 57 | + u32 mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset)); |
| 58 | + struct au1000_gpio_chip *gpch; |
| 59 | + unsigned long flags; |
| 60 | + |
| 61 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
50 | 62 |
|
51 | | - gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); |
| 63 | + local_irq_save(flags); |
| 64 | + writel(mask, gpch->regbase + AU1000_GPIO2_OUT); |
| 65 | + local_irq_restore(flags); |
52 | 66 | } |
53 | 67 |
|
54 | | -static int au1xxx_gpio2_direction_input(unsigned gpio) |
| 68 | +static int au1000_gpio2_direction_input(struct gpio_chip *chip, unsigned offset) |
55 | 69 | { |
56 | | - gpio -= AU1XXX_GPIO_BASE; |
57 | | - gpio2->dir &= ~(0x01 << gpio); |
| 70 | + u32 mask = 1 << offset; |
| 71 | + u32 tmp; |
| 72 | + struct au1000_gpio_chip *gpch; |
| 73 | + unsigned long flags; |
| 74 | + |
| 75 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 76 | + |
| 77 | + local_irq_save(flags); |
| 78 | + tmp = readl(gpch->regbase + AU1000_GPIO2_DIR); |
| 79 | + tmp &= ~mask; |
| 80 | + writel(tmp, gpch->regbase + AU1000_GPIO2_DIR); |
| 81 | + local_irq_restore(flags); |
| 82 | + |
58 | 83 | return 0; |
59 | 84 | } |
60 | 85 |
|
61 | | -static int au1xxx_gpio2_direction_output(unsigned gpio, int value) |
| 86 | +static int au1000_gpio2_direction_output(struct gpio_chip *chip, |
| 87 | + unsigned offset, int value) |
62 | 88 | { |
63 | | - gpio -= AU1XXX_GPIO_BASE; |
64 | | - gpio2->dir |= 0x01 << gpio; |
65 | | - gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); |
| 89 | + u32 mask = 1 << offset; |
| 90 | + u32 out_mask = ((GPIO2_OUT_EN_MASK << offset) | (!!value << offset)); |
| 91 | + u32 tmp; |
| 92 | + struct au1000_gpio_chip *gpch; |
| 93 | + unsigned long flags; |
| 94 | + |
| 95 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 96 | + |
| 97 | + local_irq_save(flags); |
| 98 | + tmp = readl(gpch->regbase + AU1000_GPIO2_DIR); |
| 99 | + tmp |= mask; |
| 100 | + writel(tmp, gpch->regbase + AU1000_GPIO2_DIR); |
| 101 | + writel(out_mask, gpch->regbase + AU1000_GPIO2_OUT); |
| 102 | + local_irq_restore(flags); |
| 103 | + |
66 | 104 | return 0; |
67 | 105 | } |
68 | | - |
69 | 106 | #endif /* !defined(CONFIG_SOC_AU1000) */ |
70 | 107 |
|
71 | | -static int au1xxx_gpio1_read(unsigned gpio) |
| 108 | +static int au1000_gpio1_get(struct gpio_chip *chip, unsigned offset) |
72 | 109 | { |
73 | | - return (gpio1->pinstaterd >> gpio) & 0x01; |
| 110 | + u32 mask = 1 << offset; |
| 111 | + struct au1000_gpio_chip *gpch; |
| 112 | + |
| 113 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 114 | + return readl(gpch->regbase + AU1000_GPIO1_ST) & mask; |
74 | 115 | } |
75 | 116 |
|
76 | | -static void au1xxx_gpio1_write(unsigned gpio, int value) |
| 117 | +static void au1000_gpio1_set(struct gpio_chip *chip, |
| 118 | + unsigned offset, int value) |
77 | 119 | { |
| 120 | + u32 mask = 1 << offset; |
| 121 | + u32 reg_offset; |
| 122 | + struct au1000_gpio_chip *gpch; |
| 123 | + unsigned long flags; |
| 124 | + |
| 125 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 126 | + |
78 | 127 | if (value) |
79 | | - gpio1->outputset = (0x01 << gpio); |
| 128 | + reg_offset = AU1000_GPIO1_OUT; |
80 | 129 | else |
81 | | - /* Output a zero */ |
82 | | - gpio1->outputclr = (0x01 << gpio); |
83 | | -} |
| 130 | + reg_offset = AU1000_GPIO1_CLR; |
84 | 131 |
|
85 | | -static int au1xxx_gpio1_direction_input(unsigned gpio) |
86 | | -{ |
87 | | - gpio1->pininputen = (0x01 << gpio); |
88 | | - return 0; |
| 132 | + local_irq_save(flags); |
| 133 | + writel(mask, gpch->regbase + reg_offset); |
| 134 | + local_irq_restore(flags); |
89 | 135 | } |
90 | 136 |
|
91 | | -static int au1xxx_gpio1_direction_output(unsigned gpio, int value) |
| 137 | +static int au1000_gpio1_direction_input(struct gpio_chip *chip, unsigned offset) |
92 | 138 | { |
93 | | - gpio1->trioutclr = (0x01 & gpio); |
94 | | - au1xxx_gpio1_write(gpio, value); |
| 139 | + u32 mask = 1 << offset; |
| 140 | + struct au1000_gpio_chip *gpch; |
| 141 | + |
| 142 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
| 143 | + writel(mask, gpch->regbase + AU1000_GPIO1_ST); |
| 144 | + |
95 | 145 | return 0; |
96 | 146 | } |
97 | 147 |
|
98 | | -int au1xxx_gpio_get_value(unsigned gpio) |
| 148 | +static int au1000_gpio1_direction_output(struct gpio_chip *chip, |
| 149 | + unsigned offset, int value) |
99 | 150 | { |
100 | | - if (gpio >= AU1XXX_GPIO_BASE) |
101 | | -#if defined(CONFIG_SOC_AU1000) |
102 | | - return 0; |
103 | | -#else |
104 | | - return au1xxx_gpio2_read(gpio); |
105 | | -#endif |
106 | | - else |
107 | | - return au1xxx_gpio1_read(gpio); |
108 | | -} |
109 | | -EXPORT_SYMBOL(au1xxx_gpio_get_value); |
| 151 | + u32 mask = 1 << offset; |
| 152 | + struct au1000_gpio_chip *gpch; |
110 | 153 |
|
111 | | -void au1xxx_gpio_set_value(unsigned gpio, int value) |
112 | | -{ |
113 | | - if (gpio >= AU1XXX_GPIO_BASE) |
114 | | -#if defined(CONFIG_SOC_AU1000) |
115 | | - ; |
116 | | -#else |
117 | | - au1xxx_gpio2_write(gpio, value); |
118 | | -#endif |
119 | | - else |
120 | | - au1xxx_gpio1_write(gpio, value); |
121 | | -} |
122 | | -EXPORT_SYMBOL(au1xxx_gpio_set_value); |
| 154 | + gpch = container_of(chip, struct au1000_gpio_chip, chip); |
123 | 155 |
|
124 | | -int au1xxx_gpio_direction_input(unsigned gpio) |
125 | | -{ |
126 | | - if (gpio >= AU1XXX_GPIO_BASE) |
127 | | -#if defined(CONFIG_SOC_AU1000) |
128 | | - return -ENODEV; |
129 | | -#else |
130 | | - return au1xxx_gpio2_direction_input(gpio); |
131 | | -#endif |
| 156 | + writel(mask, gpch->regbase + AU1000_GPIO1_TRI_OUT); |
| 157 | + au1000_gpio1_set(chip, offset, value); |
132 | 158 |
|
133 | | - return au1xxx_gpio1_direction_input(gpio); |
| 159 | + return 0; |
134 | 160 | } |
135 | | -EXPORT_SYMBOL(au1xxx_gpio_direction_input); |
136 | 161 |
|
137 | | -int au1xxx_gpio_direction_output(unsigned gpio, int value) |
| 162 | +struct au1000_gpio_chip au1000_gpio_chip[] = { |
| 163 | + [0] = { |
| 164 | + .regbase = (void __iomem *)SYS_BASE, |
| 165 | + .chip = { |
| 166 | + .label = "au1000-gpio1", |
| 167 | + .direction_input = au1000_gpio1_direction_input, |
| 168 | + .direction_output = au1000_gpio1_direction_output, |
| 169 | + .get = au1000_gpio1_get, |
| 170 | + .set = au1000_gpio1_set, |
| 171 | + .base = 0, |
| 172 | + .ngpio = 32, |
| 173 | + }, |
| 174 | + }, |
| 175 | +#if !defined(CONFIG_SOC_AU1000) |
| 176 | + [1] = { |
| 177 | + .regbase = (void __iomem *)GPIO2_BASE, |
| 178 | + .chip = { |
| 179 | + .label = "au1000-gpio2", |
| 180 | + .direction_input = au1000_gpio2_direction_input, |
| 181 | + .direction_output = au1000_gpio2_direction_output, |
| 182 | + .get = au1000_gpio2_get, |
| 183 | + .set = au1000_gpio2_set, |
| 184 | + .base = AU1XXX_GPIO_BASE, |
| 185 | + .ngpio = 32, |
| 186 | + }, |
| 187 | + }, |
| 188 | +#endif |
| 189 | +}; |
| 190 | + |
| 191 | +static int __init au1000_gpio_init(void) |
138 | 192 | { |
139 | | - if (gpio >= AU1XXX_GPIO_BASE) |
140 | | -#if defined(CONFIG_SOC_AU1000) |
141 | | - return -ENODEV; |
142 | | -#else |
143 | | - return au1xxx_gpio2_direction_output(gpio, value); |
| 193 | + gpiochip_add(&au1000_gpio_chip[0].chip); |
| 194 | +#if !defined(CONFIG_SOC_AU1000) |
| 195 | + gpiochip_add(&au1000_gpio_chip[1].chip); |
144 | 196 | #endif |
145 | 197 |
|
146 | | - return au1xxx_gpio1_direction_output(gpio, value); |
| 198 | + return 0; |
147 | 199 | } |
148 | | -EXPORT_SYMBOL(au1xxx_gpio_direction_output); |
| 200 | +arch_initcall(au1000_gpio_init); |
| 201 | + |
0 commit comments