aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/blackfin/mach-bf548/gpio.c87
-rw-r--r--include/asm-blackfin/mach-bf548/gpio.h5
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
50static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; 50static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
51static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; 51static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
52char *str_ident = NULL;
53
54#define RESOURCE_LABEL_SIZE 16
52 55
53inline int check_gpio(unsigned short gpio) 56inline 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
76inline u16 get_portmux(unsigned short portno) 78inline 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
86static void port_setup(unsigned short gpio, unsigned short usage) 87static 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
99static int __init bfin_gpio_init(void) 96static 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
106arch_initcall(bfin_gpio_init); 108arch_initcall(bfin_gpio_init);
107 109
110static 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
121static 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
130static 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
108int peripheral_request(unsigned short per, const char *label) 139int 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
196anyway:
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
155int peripheral_request_list(unsigned short per[], const char *label) 209int 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
213int gpio_request(unsigned short gpio, const char *label);
214void peripheral_free(unsigned short per);
215int peripheral_request_list(unsigned short per[], const char *label);
216void peripheral_free_list(unsigned short per[]);