diff options
-rw-r--r-- | arch/blackfin/mach-bf548/gpio.c | 87 | ||||
-rw-r--r-- | include/asm-blackfin/mach-bf548/gpio.h | 5 |
2 files changed, 72 insertions, 20 deletions
diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c index 0da5f0003b8c..c073ab36066d 100644 --- a/arch/blackfin/mach-bf548/gpio.c +++ b/arch/blackfin/mach-bf548/gpio.c | |||
@@ -49,6 +49,9 @@ static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { | |||
49 | 49 | ||
50 | static unsigned short reserved_gpio_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)]; | 51 | static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; |
52 | char *str_ident = NULL; | ||
53 | |||
54 | #define RESOURCE_LABEL_SIZE 16 | ||
52 | 55 | ||
53 | inline int check_gpio(unsigned short gpio) | 56 | inline int check_gpio(unsigned short gpio) |
54 | { | 57 | { |
@@ -70,7 +73,6 @@ inline void portmux_setup(unsigned short portno, unsigned short function) | |||
70 | pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); | 73 | pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); |
71 | 74 | ||
72 | gpio_array[gpio_bank(portno)]->port_mux = pmux; | 75 | gpio_array[gpio_bank(portno)]->port_mux = pmux; |
73 | |||
74 | } | 76 | } |
75 | 77 | ||
76 | inline u16 get_portmux(unsigned short portno) | 78 | inline u16 get_portmux(unsigned short portno) |
@@ -80,16 +82,11 @@ inline u16 get_portmux(unsigned short portno) | |||
80 | pmux = gpio_array[gpio_bank(portno)]->port_mux; | 82 | pmux = gpio_array[gpio_bank(portno)]->port_mux; |
81 | 83 | ||
82 | return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); | 84 | return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); |
83 | |||
84 | } | 85 | } |
85 | 86 | ||
86 | static void port_setup(unsigned short gpio, unsigned short usage) | 87 | static void port_setup(unsigned short gpio, unsigned short usage) |
87 | { | 88 | { |
88 | if (usage == GPIO_USAGE) { | 89 | if (usage == GPIO_USAGE) { |
89 | if (gpio_array[gpio_bank(gpio)]->port_fer & gpio_bit(gpio)) | ||
90 | printk(KERN_WARNING | ||
91 | "bfin-gpio: Possible Conflict with Peripheral " | ||
92 | "usage and GPIO %d detected!\n", gpio); | ||
93 | gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); | 90 | gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); |
94 | } else | 91 | } else |
95 | gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); | 92 | gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); |
@@ -98,6 +95,11 @@ static void port_setup(unsigned short gpio, unsigned short usage) | |||
98 | 95 | ||
99 | static int __init bfin_gpio_init(void) | 96 | static int __init bfin_gpio_init(void) |
100 | { | 97 | { |
98 | |||
99 | str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL); | ||
100 | if (!str_ident) | ||
101 | return -ENOMEM; | ||
102 | |||
101 | printk(KERN_INFO "Blackfin GPIO Controller\n"); | 103 | printk(KERN_INFO "Blackfin GPIO Controller\n"); |
102 | 104 | ||
103 | return 0; | 105 | return 0; |
@@ -105,11 +107,47 @@ static int __init bfin_gpio_init(void) | |||
105 | 107 | ||
106 | arch_initcall(bfin_gpio_init); | 108 | arch_initcall(bfin_gpio_init); |
107 | 109 | ||
110 | static void set_label(unsigned short ident, const char *label) | ||
111 | { | ||
112 | |||
113 | if (label && str_ident) { | ||
114 | strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label, | ||
115 | RESOURCE_LABEL_SIZE); | ||
116 | str_ident[ident * RESOURCE_LABEL_SIZE + | ||
117 | RESOURCE_LABEL_SIZE - 1] = 0; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static char *get_label(unsigned short ident) | ||
122 | { | ||
123 | if (!str_ident) | ||
124 | return "UNKNOWN"; | ||
125 | |||
126 | return (str_ident[ident * RESOURCE_LABEL_SIZE] ? | ||
127 | (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN"); | ||
128 | } | ||
129 | |||
130 | static int cmp_label(unsigned short ident, const char *label) | ||
131 | { | ||
132 | if (label && str_ident) | ||
133 | return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE, | ||
134 | label, strlen(label)); | ||
135 | else | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
108 | int peripheral_request(unsigned short per, const char *label) | 139 | int peripheral_request(unsigned short per, const char *label) |
109 | { | 140 | { |
110 | unsigned long flags; | 141 | unsigned long flags; |
111 | unsigned short ident = P_IDENT(per); | 142 | unsigned short ident = P_IDENT(per); |
112 | 143 | ||
144 | /* | ||
145 | * Don't cares are pins with only one dedicated function | ||
146 | */ | ||
147 | |||
148 | if (per & P_DONTCARE) | ||
149 | return 0; | ||
150 | |||
113 | if (!(per & P_DEFINED)) | 151 | if (!(per & P_DEFINED)) |
114 | return -ENODEV; | 152 | return -ENODEV; |
115 | 153 | ||
@@ -120,8 +158,8 @@ int peripheral_request(unsigned short per, const char *label) | |||
120 | 158 | ||
121 | if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { | 159 | if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { |
122 | printk(KERN_ERR | 160 | printk(KERN_ERR |
123 | "%s: Peripheral %d is already reserved as GPIO!\n", | 161 | "%s: Peripheral %d is already reserved as GPIO by %s !\n", |
124 | __FUNCTION__, per); | 162 | __FUNCTION__, ident, get_label(ident)); |
125 | dump_stack(); | 163 | dump_stack(); |
126 | local_irq_restore(flags); | 164 | local_irq_restore(flags); |
127 | return -EBUSY; | 165 | return -EBUSY; |
@@ -131,22 +169,38 @@ int peripheral_request(unsigned short per, const char *label) | |||
131 | 169 | ||
132 | u16 funct = get_portmux(ident); | 170 | u16 funct = get_portmux(ident); |
133 | 171 | ||
172 | /* | ||
173 | * Pin functions like AMC address strobes my | ||
174 | * be requested and used by several drivers | ||
175 | */ | ||
176 | |||
134 | if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { | 177 | if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { |
178 | |||
179 | /* | ||
180 | * Allow that the identical pin function can | ||
181 | * be requested from the same driver twice | ||
182 | */ | ||
183 | |||
184 | if (cmp_label(ident, label) == 0) | ||
185 | goto anyway; | ||
186 | |||
135 | printk(KERN_ERR | 187 | printk(KERN_ERR |
136 | "%s: Peripheral %d is already reserved!\n", | 188 | "%s: Peripheral %d function %d is already reserved by %s !\n", |
137 | __FUNCTION__, per); | 189 | __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); |
138 | dump_stack(); | 190 | dump_stack(); |
139 | local_irq_restore(flags); | 191 | local_irq_restore(flags); |
140 | return -EBUSY; | 192 | return -EBUSY; |
141 | } | 193 | } |
142 | } | 194 | } |
143 | 195 | ||
196 | anyway: | ||
144 | reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); | 197 | reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); |
145 | 198 | ||
146 | portmux_setup(ident, P_FUNCT2MUX(per)); | 199 | portmux_setup(ident, P_FUNCT2MUX(per)); |
147 | port_setup(ident, PERIPHERAL_USAGE); | 200 | port_setup(ident, PERIPHERAL_USAGE); |
148 | 201 | ||
149 | local_irq_restore(flags); | 202 | local_irq_restore(flags); |
203 | set_label(ident, label); | ||
150 | 204 | ||
151 | return 0; | 205 | return 0; |
152 | } | 206 | } |
@@ -154,7 +208,6 @@ EXPORT_SYMBOL(peripheral_request); | |||
154 | 208 | ||
155 | int peripheral_request_list(unsigned short per[], const char *label) | 209 | int peripheral_request_list(unsigned short per[], const char *label) |
156 | { | 210 | { |
157 | |||
158 | u16 cnt; | 211 | u16 cnt; |
159 | int ret; | 212 | int ret; |
160 | 213 | ||
@@ -173,6 +226,9 @@ void peripheral_free(unsigned short per) | |||
173 | unsigned long flags; | 226 | unsigned long flags; |
174 | unsigned short ident = P_IDENT(per); | 227 | unsigned short ident = P_IDENT(per); |
175 | 228 | ||
229 | if (per & P_DONTCARE) | ||
230 | return; | ||
231 | |||
176 | if (!(per & P_DEFINED)) | 232 | if (!(per & P_DEFINED)) |
177 | return; | 233 | return; |
178 | 234 | ||
@@ -182,8 +238,6 @@ void peripheral_free(unsigned short per) | |||
182 | local_irq_save(flags); | 238 | local_irq_save(flags); |
183 | 239 | ||
184 | if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { | 240 | 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); | 241 | local_irq_restore(flags); |
188 | return; | 242 | return; |
189 | } | 243 | } |
@@ -234,7 +288,8 @@ int gpio_request(unsigned short gpio, const char *label) | |||
234 | local_irq_save(flags); | 288 | local_irq_save(flags); |
235 | 289 | ||
236 | if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | 290 | if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { |
237 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); | 291 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", |
292 | gpio, get_label(gpio)); | ||
238 | dump_stack(); | 293 | dump_stack(); |
239 | local_irq_restore(flags); | 294 | local_irq_restore(flags); |
240 | return -EBUSY; | 295 | return -EBUSY; |
@@ -242,7 +297,8 @@ int gpio_request(unsigned short gpio, const char *label) | |||
242 | 297 | ||
243 | if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | 298 | if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { |
244 | printk(KERN_ERR | 299 | printk(KERN_ERR |
245 | "bfin-gpio: GPIO %d is already reserved as Peripheral!\n", gpio); | 300 | "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", |
301 | gpio, get_label(gpio)); | ||
246 | dump_stack(); | 302 | dump_stack(); |
247 | local_irq_restore(flags); | 303 | local_irq_restore(flags); |
248 | return -EBUSY; | 304 | return -EBUSY; |
@@ -253,6 +309,7 @@ int gpio_request(unsigned short gpio, const char *label) | |||
253 | local_irq_restore(flags); | 309 | local_irq_restore(flags); |
254 | 310 | ||
255 | port_setup(gpio, GPIO_USAGE); | 311 | port_setup(gpio, GPIO_USAGE); |
312 | set_label(gpio, label); | ||
256 | 313 | ||
257 | return 0; | 314 | return 0; |
258 | } | 315 | } |
diff --git a/include/asm-blackfin/mach-bf548/gpio.h b/include/asm-blackfin/mach-bf548/gpio.h index dbf66bcabe35..cb8b0f15c9a6 100644 --- a/include/asm-blackfin/mach-bf548/gpio.h +++ b/include/asm-blackfin/mach-bf548/gpio.h | |||
@@ -209,8 +209,3 @@ struct gpio_port_t { | |||
209 | unsigned short dummy7; | 209 | unsigned short dummy7; |
210 | unsigned int port_mux; | 210 | unsigned int port_mux; |
211 | }; | 211 | }; |
212 | |||
213 | int gpio_request(unsigned short gpio, const char *label); | ||
214 | void peripheral_free(unsigned short per); | ||
215 | int peripheral_request_list(unsigned short per[], const char *label); | ||
216 | void peripheral_free_list(unsigned short per[]); | ||