diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2007-07-12 00:32:52 -0400 |
---|---|---|
committer | Bryan Wu <bryan.wu@analog.com> | 2007-07-12 00:32:52 -0400 |
commit | 5610db61cf2945a5e74667e952f2792c96ba53a1 (patch) | |
tree | 982c8cdb8267ac0a162b4de5d3d3b545adcff602 /arch/blackfin | |
parent | 520473b0775ce046d179afa686fb3222884c389d (diff) |
Blackfin arch: Add Support for Peripheral PortMux and resouce allocation
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Diffstat (limited to 'arch/blackfin')
-rw-r--r-- | arch/blackfin/mach-bf548/gpio.c | 189 |
1 files changed, 160 insertions, 29 deletions
diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c index 9b1a00aabf28..0da5f0003b8c 100644 --- a/arch/blackfin/mach-bf548/gpio.c +++ b/arch/blackfin/mach-bf548/gpio.c | |||
@@ -31,38 +31,64 @@ | |||
31 | #include <linux/err.h> | 31 | #include <linux/err.h> |
32 | #include <asm/blackfin.h> | 32 | #include <asm/blackfin.h> |
33 | #include <asm/gpio.h> | 33 | #include <asm/gpio.h> |
34 | #include <asm/portmux.h> | ||
34 | #include <linux/irq.h> | 35 | #include <linux/irq.h> |
35 | 36 | ||
36 | static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { | 37 | static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { |
37 | (struct gpio_port_t *) PORTA_FER, | 38 | (struct gpio_port_t *)PORTA_FER, |
38 | (struct gpio_port_t *) PORTB_FER, | 39 | (struct gpio_port_t *)PORTB_FER, |
39 | (struct gpio_port_t *) PORTC_FER, | 40 | (struct gpio_port_t *)PORTC_FER, |
40 | (struct gpio_port_t *) PORTD_FER, | 41 | (struct gpio_port_t *)PORTD_FER, |
41 | (struct gpio_port_t *) PORTE_FER, | 42 | (struct gpio_port_t *)PORTE_FER, |
42 | (struct gpio_port_t *) PORTF_FER, | 43 | (struct gpio_port_t *)PORTF_FER, |
43 | (struct gpio_port_t *) PORTG_FER, | 44 | (struct gpio_port_t *)PORTG_FER, |
44 | (struct gpio_port_t *) PORTH_FER, | 45 | (struct gpio_port_t *)PORTH_FER, |
45 | (struct gpio_port_t *) PORTI_FER, | 46 | (struct gpio_port_t *)PORTI_FER, |
46 | (struct gpio_port_t *) PORTJ_FER, | 47 | (struct gpio_port_t *)PORTJ_FER, |
47 | }; | 48 | }; |
48 | 49 | ||
49 | static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; | 50 | static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; |
51 | static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; | ||
50 | 52 | ||
51 | inline int check_gpio(unsigned short gpio) | 53 | inline int check_gpio(unsigned short gpio) |
52 | { | 54 | { |
53 | if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 \ | 55 | if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 |
54 | || gpio == GPIO_PH14 || gpio == GPIO_PH15 \ | 56 | || gpio == GPIO_PH14 || gpio == GPIO_PH15 |
55 | || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 \ | 57 | || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 |
56 | || gpio > MAX_BLACKFIN_GPIOS) | 58 | || gpio > MAX_BLACKFIN_GPIOS) |
57 | return -EINVAL; | 59 | return -EINVAL; |
58 | return 0; | 60 | return 0; |
59 | } | 61 | } |
60 | 62 | ||
63 | inline void portmux_setup(unsigned short portno, unsigned short function) | ||
64 | { | ||
65 | u32 pmux; | ||
66 | |||
67 | pmux = gpio_array[gpio_bank(portno)]->port_mux; | ||
68 | |||
69 | pmux &= ~(0x3 << (2 * gpio_sub_n(portno))); | ||
70 | pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); | ||
71 | |||
72 | gpio_array[gpio_bank(portno)]->port_mux = pmux; | ||
73 | |||
74 | } | ||
75 | |||
76 | inline u16 get_portmux(unsigned short portno) | ||
77 | { | ||
78 | u32 pmux; | ||
79 | |||
80 | pmux = gpio_array[gpio_bank(portno)]->port_mux; | ||
81 | |||
82 | return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); | ||
83 | |||
84 | } | ||
85 | |||
61 | static void port_setup(unsigned short gpio, unsigned short usage) | 86 | static void port_setup(unsigned short gpio, unsigned short usage) |
62 | { | 87 | { |
63 | if (usage == GPIO_USAGE) { | 88 | if (usage == GPIO_USAGE) { |
64 | if (gpio_array[gpio_bank(gpio)]->port_fer & gpio_bit(gpio)) | 89 | if (gpio_array[gpio_bank(gpio)]->port_fer & gpio_bit(gpio)) |
65 | printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral " | 90 | printk(KERN_WARNING |
91 | "bfin-gpio: Possible Conflict with Peripheral " | ||
66 | "usage and GPIO %d detected!\n", gpio); | 92 | "usage and GPIO %d detected!\n", gpio); |
67 | gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); | 93 | gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); |
68 | } else | 94 | } else |
@@ -72,18 +98,116 @@ static void port_setup(unsigned short gpio, unsigned short usage) | |||
72 | 98 | ||
73 | static int __init bfin_gpio_init(void) | 99 | static int __init bfin_gpio_init(void) |
74 | { | 100 | { |
75 | int i; | ||
76 | |||
77 | printk(KERN_INFO "Blackfin GPIO Controller\n"); | 101 | printk(KERN_INFO "Blackfin GPIO Controller\n"); |
78 | 102 | ||
79 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) | ||
80 | reserved_map[gpio_bank(i)] = 0; | ||
81 | |||
82 | return 0; | 103 | return 0; |
83 | } | 104 | } |
84 | 105 | ||
85 | arch_initcall(bfin_gpio_init); | 106 | arch_initcall(bfin_gpio_init); |
86 | 107 | ||
108 | int peripheral_request(unsigned short per, const char *label) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | unsigned short ident = P_IDENT(per); | ||
112 | |||
113 | if (!(per & P_DEFINED)) | ||
114 | return -ENODEV; | ||
115 | |||
116 | if (check_gpio(ident) < 0) | ||
117 | return -EINVAL; | ||
118 | |||
119 | local_irq_save(flags); | ||
120 | |||
121 | if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { | ||
122 | printk(KERN_ERR | ||
123 | "%s: Peripheral %d is already reserved as GPIO!\n", | ||
124 | __FUNCTION__, per); | ||
125 | dump_stack(); | ||
126 | local_irq_restore(flags); | ||
127 | return -EBUSY; | ||
128 | } | ||
129 | |||
130 | if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { | ||
131 | |||
132 | u16 funct = get_portmux(ident); | ||
133 | |||
134 | if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { | ||
135 | printk(KERN_ERR | ||
136 | "%s: Peripheral %d is already reserved!\n", | ||
137 | __FUNCTION__, per); | ||
138 | dump_stack(); | ||
139 | local_irq_restore(flags); | ||
140 | return -EBUSY; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); | ||
145 | |||
146 | portmux_setup(ident, P_FUNCT2MUX(per)); | ||
147 | port_setup(ident, PERIPHERAL_USAGE); | ||
148 | |||
149 | local_irq_restore(flags); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | EXPORT_SYMBOL(peripheral_request); | ||
154 | |||
155 | int peripheral_request_list(unsigned short per[], const char *label) | ||
156 | { | ||
157 | |||
158 | u16 cnt; | ||
159 | int ret; | ||
160 | |||
161 | for (cnt = 0; per[cnt] != 0; cnt++) { | ||
162 | ret = peripheral_request(per[cnt], label); | ||
163 | if (ret < 0) | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | EXPORT_SYMBOL(peripheral_request_list); | ||
170 | |||
171 | void peripheral_free(unsigned short per) | ||
172 | { | ||
173 | unsigned long flags; | ||
174 | unsigned short ident = P_IDENT(per); | ||
175 | |||
176 | if (!(per & P_DEFINED)) | ||
177 | return; | ||
178 | |||
179 | if (check_gpio(ident) < 0) | ||
180 | return; | ||
181 | |||
182 | local_irq_save(flags); | ||
183 | |||
184 | if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { | ||
185 | printk(KERN_ERR "bfin-gpio: Peripheral %d wasn't reserved!\n", per); | ||
186 | dump_stack(); | ||
187 | local_irq_restore(flags); | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | if (!(per & P_MAYSHARE)) { | ||
192 | port_setup(ident, GPIO_USAGE); | ||
193 | } | ||
194 | |||
195 | reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); | ||
196 | |||
197 | local_irq_restore(flags); | ||
198 | } | ||
199 | EXPORT_SYMBOL(peripheral_free); | ||
200 | |||
201 | void peripheral_free_list(unsigned short per[]) | ||
202 | { | ||
203 | u16 cnt; | ||
204 | |||
205 | for (cnt = 0; per[cnt] != 0; cnt++) { | ||
206 | peripheral_free(per[cnt]); | ||
207 | } | ||
208 | |||
209 | } | ||
210 | EXPORT_SYMBOL(peripheral_free_list); | ||
87 | 211 | ||
88 | /*********************************************************** | 212 | /*********************************************************** |
89 | * | 213 | * |
@@ -109,13 +233,22 @@ int gpio_request(unsigned short gpio, const char *label) | |||
109 | 233 | ||
110 | local_irq_save(flags); | 234 | local_irq_save(flags); |
111 | 235 | ||
112 | if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | 236 | if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { |
113 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); | 237 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); |
114 | dump_stack(); | 238 | dump_stack(); |
115 | local_irq_restore(flags); | 239 | local_irq_restore(flags); |
116 | return -EBUSY; | 240 | return -EBUSY; |
117 | } | 241 | } |
118 | reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio); | 242 | |
243 | if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | ||
244 | printk(KERN_ERR | ||
245 | "bfin-gpio: GPIO %d is already reserved as Peripheral!\n", gpio); | ||
246 | dump_stack(); | ||
247 | local_irq_restore(flags); | ||
248 | return -EBUSY; | ||
249 | } | ||
250 | |||
251 | reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); | ||
119 | 252 | ||
120 | local_irq_restore(flags); | 253 | local_irq_restore(flags); |
121 | 254 | ||
@@ -125,7 +258,6 @@ int gpio_request(unsigned short gpio, const char *label) | |||
125 | } | 258 | } |
126 | EXPORT_SYMBOL(gpio_request); | 259 | EXPORT_SYMBOL(gpio_request); |
127 | 260 | ||
128 | |||
129 | void gpio_free(unsigned short gpio) | 261 | void gpio_free(unsigned short gpio) |
130 | { | 262 | { |
131 | unsigned long flags; | 263 | unsigned long flags; |
@@ -135,25 +267,24 @@ void gpio_free(unsigned short gpio) | |||
135 | 267 | ||
136 | local_irq_save(flags); | 268 | local_irq_save(flags); |
137 | 269 | ||
138 | if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { | 270 | if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { |
139 | printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio); | 271 | printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio); |
140 | dump_stack(); | 272 | dump_stack(); |
141 | local_irq_restore(flags); | 273 | local_irq_restore(flags); |
142 | return; | 274 | return; |
143 | } | 275 | } |
144 | 276 | ||
145 | reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); | 277 | reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); |
146 | 278 | ||
147 | local_irq_restore(flags); | 279 | local_irq_restore(flags); |
148 | } | 280 | } |
149 | EXPORT_SYMBOL(gpio_free); | 281 | EXPORT_SYMBOL(gpio_free); |
150 | 282 | ||
151 | |||
152 | void gpio_direction_input(unsigned short gpio) | 283 | void gpio_direction_input(unsigned short gpio) |
153 | { | 284 | { |
154 | unsigned long flags; | 285 | unsigned long flags; |
155 | 286 | ||
156 | BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); | 287 | BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); |
157 | 288 | ||
158 | local_irq_save(flags); | 289 | local_irq_save(flags); |
159 | gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); | 290 | gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); |
@@ -166,7 +297,7 @@ void gpio_direction_output(unsigned short gpio) | |||
166 | { | 297 | { |
167 | unsigned long flags; | 298 | unsigned long flags; |
168 | 299 | ||
169 | BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); | 300 | BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); |
170 | 301 | ||
171 | local_irq_save(flags); | 302 | local_irq_save(flags); |
172 | gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); | 303 | gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); |