diff options
Diffstat (limited to 'arch/cris/arch-v32')
-rw-r--r-- | arch/cris/arch-v32/drivers/mach-a3/gpio.c | 348 |
1 files changed, 174 insertions, 174 deletions
diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c index 30a2b6e526df..de107dad9f4f 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c | |||
@@ -72,13 +72,13 @@ static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, | |||
72 | unsigned long arg); | 72 | unsigned long arg); |
73 | #endif | 73 | #endif |
74 | static int gpio_ioctl(struct inode *inode, struct file *file, | 74 | static int gpio_ioctl(struct inode *inode, struct file *file, |
75 | unsigned int cmd, unsigned long arg); | 75 | unsigned int cmd, unsigned long arg); |
76 | static ssize_t gpio_write(struct file *file, const char *buf, size_t count, | 76 | static ssize_t gpio_write(struct file *file, const char __user *buf, |
77 | loff_t *off); | 77 | size_t count, loff_t *off); |
78 | static int gpio_open(struct inode *inode, struct file *filp); | 78 | static int gpio_open(struct inode *inode, struct file *filp); |
79 | static int gpio_release(struct inode *inode, struct file *filp); | 79 | static int gpio_release(struct inode *inode, struct file *filp); |
80 | static unsigned int gpio_poll(struct file *filp, | 80 | static unsigned int gpio_poll(struct file *filp, |
81 | struct poll_table_struct *wait); | 81 | struct poll_table_struct *wait); |
82 | 82 | ||
83 | /* private data per open() of this driver */ | 83 | /* private data per open() of this driver */ |
84 | 84 | ||
@@ -96,6 +96,10 @@ struct gpio_private { | |||
96 | }; | 96 | }; |
97 | 97 | ||
98 | static void gpio_set_alarm(struct gpio_private *priv); | 98 | static void gpio_set_alarm(struct gpio_private *priv); |
99 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); | ||
100 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, | ||
101 | unsigned long arg); | ||
102 | |||
99 | 103 | ||
100 | /* linked list of alarms to check for */ | 104 | /* linked list of alarms to check for */ |
101 | 105 | ||
@@ -103,23 +107,23 @@ static struct gpio_private *alarmlist; | |||
103 | 107 | ||
104 | static int wanted_interrupts; | 108 | static int wanted_interrupts; |
105 | 109 | ||
106 | static DEFINE_SPINLOCK(alarm_lock); | 110 | static DEFINE_SPINLOCK(gpio_lock); |
107 | 111 | ||
108 | #define NUM_PORTS (GPIO_MINOR_LAST+1) | 112 | #define NUM_PORTS (GPIO_MINOR_LAST+1) |
109 | #define GIO_REG_RD_ADDR(reg) \ | 113 | #define GIO_REG_RD_ADDR(reg) \ |
110 | (volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) | 114 | (unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) |
111 | #define GIO_REG_WR_ADDR(reg) \ | 115 | #define GIO_REG_WR_ADDR(reg) \ |
112 | (volatile unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg) | 116 | (unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg) |
113 | unsigned long led_dummy; | 117 | static unsigned long led_dummy; |
114 | unsigned long port_d_dummy; /* Only input on Artpec-3 */ | 118 | static unsigned long port_d_dummy; /* Only input on Artpec-3 */ |
115 | unsigned long port_e_dummy; /* Non existent on Artpec-3 */ | ||
116 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | 119 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
120 | static unsigned long port_e_dummy; /* Non existent on Artpec-3 */ | ||
117 | static unsigned long virtual_dummy; | 121 | static unsigned long virtual_dummy; |
118 | static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; | 122 | static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; |
119 | static unsigned short cached_virtual_gpio_read; | 123 | static unsigned short cached_virtual_gpio_read; |
120 | #endif | 124 | #endif |
121 | 125 | ||
122 | static volatile unsigned long *data_out[NUM_PORTS] = { | 126 | static unsigned long *data_out[NUM_PORTS] = { |
123 | GIO_REG_WR_ADDR(rw_pa_dout), | 127 | GIO_REG_WR_ADDR(rw_pa_dout), |
124 | GIO_REG_WR_ADDR(rw_pb_dout), | 128 | GIO_REG_WR_ADDR(rw_pb_dout), |
125 | &led_dummy, | 129 | &led_dummy, |
@@ -131,7 +135,7 @@ static volatile unsigned long *data_out[NUM_PORTS] = { | |||
131 | #endif | 135 | #endif |
132 | }; | 136 | }; |
133 | 137 | ||
134 | static volatile unsigned long *data_in[NUM_PORTS] = { | 138 | static unsigned long *data_in[NUM_PORTS] = { |
135 | GIO_REG_RD_ADDR(r_pa_din), | 139 | GIO_REG_RD_ADDR(r_pa_din), |
136 | GIO_REG_RD_ADDR(r_pb_din), | 140 | GIO_REG_RD_ADDR(r_pb_din), |
137 | &led_dummy, | 141 | &led_dummy, |
@@ -167,7 +171,7 @@ static unsigned long changeable_bits[NUM_PORTS] = { | |||
167 | #endif | 171 | #endif |
168 | }; | 172 | }; |
169 | 173 | ||
170 | static volatile unsigned long *dir_oe[NUM_PORTS] = { | 174 | static unsigned long *dir_oe[NUM_PORTS] = { |
171 | GIO_REG_WR_ADDR(rw_pa_oe), | 175 | GIO_REG_WR_ADDR(rw_pa_oe), |
172 | GIO_REG_WR_ADDR(rw_pb_oe), | 176 | GIO_REG_WR_ADDR(rw_pb_oe), |
173 | &led_dummy, | 177 | &led_dummy, |
@@ -179,8 +183,7 @@ static volatile unsigned long *dir_oe[NUM_PORTS] = { | |||
179 | #endif | 183 | #endif |
180 | }; | 184 | }; |
181 | 185 | ||
182 | static void | 186 | static void gpio_set_alarm(struct gpio_private *priv) |
183 | gpio_set_alarm(struct gpio_private *priv) | ||
184 | { | 187 | { |
185 | int bit; | 188 | int bit; |
186 | int intr_cfg; | 189 | int intr_cfg; |
@@ -188,7 +191,7 @@ gpio_set_alarm(struct gpio_private *priv) | |||
188 | int pins; | 191 | int pins; |
189 | unsigned long flags; | 192 | unsigned long flags; |
190 | 193 | ||
191 | local_irq_save(flags); | 194 | spin_lock_irqsave(&gpio_lock, flags); |
192 | intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg); | 195 | intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg); |
193 | pins = REG_RD_INT(gio, regi_gio, rw_intr_pins); | 196 | pins = REG_RD_INT(gio, regi_gio, rw_intr_pins); |
194 | mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS; | 197 | mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS; |
@@ -218,14 +221,13 @@ gpio_set_alarm(struct gpio_private *priv) | |||
218 | REG_WR_INT(gio, regi_gio, rw_intr_pins, pins); | 221 | REG_WR_INT(gio, regi_gio, rw_intr_pins, pins); |
219 | REG_WR_INT(gio, regi_gio, rw_intr_mask, mask); | 222 | REG_WR_INT(gio, regi_gio, rw_intr_mask, mask); |
220 | 223 | ||
221 | local_irq_restore(flags); | 224 | spin_unlock_irqrestore(&gpio_lock, flags); |
222 | } | 225 | } |
223 | 226 | ||
224 | static unsigned int | 227 | static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) |
225 | gpio_poll(struct file *file, struct poll_table_struct *wait) | ||
226 | { | 228 | { |
227 | unsigned int mask = 0; | 229 | unsigned int mask = 0; |
228 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 230 | struct gpio_private *priv = file->private_data; |
229 | unsigned long data; | 231 | unsigned long data; |
230 | unsigned long tmp; | 232 | unsigned long tmp; |
231 | 233 | ||
@@ -235,7 +237,7 @@ gpio_poll(struct file *file, struct poll_table_struct *wait) | |||
235 | 237 | ||
236 | poll_wait(file, &priv->alarm_wq, wait); | 238 | poll_wait(file, &priv->alarm_wq, wait); |
237 | if (priv->minor <= GPIO_MINOR_D) { | 239 | if (priv->minor <= GPIO_MINOR_D) { |
238 | data = *data_in[priv->minor]; | 240 | data = readl(data_in[priv->minor]); |
239 | REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts); | 241 | REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts); |
240 | tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask); | 242 | tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask); |
241 | tmp &= I2C_INTERRUPT_BITS; | 243 | tmp &= I2C_INTERRUPT_BITS; |
@@ -251,12 +253,12 @@ gpio_poll(struct file *file, struct poll_table_struct *wait) | |||
251 | return mask; | 253 | return mask; |
252 | } | 254 | } |
253 | 255 | ||
254 | static irqreturn_t | 256 | static irqreturn_t gpio_interrupt(int irq, void *dev_id) |
255 | gpio_interrupt(int irq, void *dev_id) | ||
256 | { | 257 | { |
257 | reg_gio_rw_intr_mask intr_mask; | 258 | reg_gio_rw_intr_mask intr_mask; |
258 | reg_gio_r_masked_intr masked_intr; | 259 | reg_gio_r_masked_intr masked_intr; |
259 | reg_gio_rw_ack_intr ack_intr; | 260 | reg_gio_rw_ack_intr ack_intr; |
261 | unsigned long flags; | ||
260 | unsigned long tmp; | 262 | unsigned long tmp; |
261 | unsigned long tmp2; | 263 | unsigned long tmp2; |
262 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | 264 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
@@ -268,9 +270,9 @@ gpio_interrupt(int irq, void *dev_id) | |||
268 | tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); | 270 | tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); |
269 | 271 | ||
270 | /* Find those that we have enabled */ | 272 | /* Find those that we have enabled */ |
271 | spin_lock(&alarm_lock); | 273 | spin_lock_irqsave(&gpio_lock, flags); |
272 | tmp &= wanted_interrupts; | 274 | tmp &= wanted_interrupts; |
273 | spin_unlock(&alarm_lock); | 275 | spin_unlock_irqrestore(&gpio_lock, flags); |
274 | 276 | ||
275 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | 277 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
276 | /* Something changed on virtual GPIO. Interrupt is acked by | 278 | /* Something changed on virtual GPIO. Interrupt is acked by |
@@ -304,15 +306,42 @@ gpio_interrupt(int irq, void *dev_id) | |||
304 | return IRQ_RETVAL(tmp); | 306 | return IRQ_RETVAL(tmp); |
305 | } | 307 | } |
306 | 308 | ||
309 | static void gpio_write_bit(unsigned long *port, unsigned char data, int bit, | ||
310 | unsigned char clk_mask, unsigned char data_mask) | ||
311 | { | ||
312 | unsigned long shadow = readl(port) & ~clk_mask; | ||
313 | writel(shadow, port); | ||
314 | if (data & 1 << bit) | ||
315 | shadow |= data_mask; | ||
316 | else | ||
317 | shadow &= ~data_mask; | ||
318 | writel(shadow, port); | ||
319 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
320 | shadow |= clk_mask; | ||
321 | writel(shadow, port); | ||
322 | } | ||
323 | |||
324 | static void gpio_write_byte(struct gpio_private *priv, unsigned long *port, | ||
325 | unsigned char data) | ||
326 | { | ||
327 | int i; | ||
328 | |||
329 | if (priv->write_msb) | ||
330 | for (i = 7; i >= 0; i--) | ||
331 | gpio_write_bit(port, data, i, priv->clk_mask, | ||
332 | priv->data_mask); | ||
333 | else | ||
334 | for (i = 0; i <= 7; i++) | ||
335 | gpio_write_bit(port, data, i, priv->clk_mask, | ||
336 | priv->data_mask); | ||
337 | } | ||
338 | |||
307 | 339 | ||
308 | static ssize_t gpio_write(struct file *file, const char *buf, size_t count, | 340 | static ssize_t gpio_write(struct file *file, const char __user *buf, |
309 | loff_t *off) | 341 | size_t count, loff_t *off) |
310 | { | 342 | { |
311 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 343 | struct gpio_private *priv = file->private_data; |
312 | unsigned char data, clk_mask, data_mask, write_msb; | ||
313 | unsigned long flags; | 344 | unsigned long flags; |
314 | unsigned long shadow; | ||
315 | volatile unsigned long *port; | ||
316 | ssize_t retval = count; | 345 | ssize_t retval = count; |
317 | /* Only bits 0-7 may be used for write operations but allow all | 346 | /* Only bits 0-7 may be used for write operations but allow all |
318 | devices except leds... */ | 347 | devices except leds... */ |
@@ -330,55 +359,25 @@ static ssize_t gpio_write(struct file *file, const char *buf, size_t count, | |||
330 | if (!access_ok(VERIFY_READ, buf, count)) | 359 | if (!access_ok(VERIFY_READ, buf, count)) |
331 | return -EFAULT; | 360 | return -EFAULT; |
332 | 361 | ||
333 | clk_mask = priv->clk_mask; | ||
334 | data_mask = priv->data_mask; | ||
335 | /* It must have been configured using the IO_CFG_WRITE_MODE */ | 362 | /* It must have been configured using the IO_CFG_WRITE_MODE */ |
336 | /* Perhaps a better error code? */ | 363 | /* Perhaps a better error code? */ |
337 | if (clk_mask == 0 || data_mask == 0) | 364 | if (priv->clk_mask == 0 || priv->data_mask == 0) |
338 | return -EPERM; | 365 | return -EPERM; |
339 | 366 | ||
340 | write_msb = priv->write_msb; | ||
341 | D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " | 367 | D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " |
342 | "msb: %i\n", | 368 | "msb: %i\n", |
343 | count, data_mask, clk_mask, write_msb)); | 369 | count, priv->data_mask, priv->clk_mask, priv->write_msb)); |
344 | port = data_out[priv->minor]; | 370 | |
345 | 371 | spin_lock_irqsave(&gpio_lock, flags); | |
346 | while (count--) { | 372 | |
347 | int i; | 373 | while (count--) |
348 | data = *buf++; | 374 | gpio_write_byte(priv, data_out[priv->minor], *buf++); |
349 | if (priv->write_msb) { | 375 | |
350 | for (i = 7; i >= 0; i--) { | 376 | spin_unlock_irqrestore(&gpio_lock, flags); |
351 | local_irq_save(flags); | ||
352 | shadow = *port; | ||
353 | *port = shadow &= ~clk_mask; | ||
354 | if (data & 1<<i) | ||
355 | *port = shadow |= data_mask; | ||
356 | else | ||
357 | *port = shadow &= ~data_mask; | ||
358 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
359 | *port = shadow |= clk_mask; | ||
360 | local_irq_restore(flags); | ||
361 | } | ||
362 | } else { | ||
363 | for (i = 0; i <= 7; i++) { | ||
364 | local_irq_save(flags); | ||
365 | shadow = *port; | ||
366 | *port = shadow &= ~clk_mask; | ||
367 | if (data & 1<<i) | ||
368 | *port = shadow |= data_mask; | ||
369 | else | ||
370 | *port = shadow &= ~data_mask; | ||
371 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
372 | *port = shadow |= clk_mask; | ||
373 | local_irq_restore(flags); | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | return retval; | 377 | return retval; |
378 | } | 378 | } |
379 | 379 | ||
380 | static int | 380 | static int gpio_open(struct inode *inode, struct file *filp) |
381 | gpio_open(struct inode *inode, struct file *filp) | ||
382 | { | 381 | { |
383 | struct gpio_private *priv; | 382 | struct gpio_private *priv; |
384 | int p = iminor(inode); | 383 | int p = iminor(inode); |
@@ -394,7 +393,7 @@ gpio_open(struct inode *inode, struct file *filp) | |||
394 | memset(priv, 0, sizeof(*priv)); | 393 | memset(priv, 0, sizeof(*priv)); |
395 | 394 | ||
396 | priv->minor = p; | 395 | priv->minor = p; |
397 | filp->private_data = (void *)priv; | 396 | filp->private_data = priv; |
398 | 397 | ||
399 | /* initialize the io/alarm struct, not for PWM ports though */ | 398 | /* initialize the io/alarm struct, not for PWM ports though */ |
400 | if (p <= GPIO_MINOR_LAST) { | 399 | if (p <= GPIO_MINOR_LAST) { |
@@ -407,17 +406,16 @@ gpio_open(struct inode *inode, struct file *filp) | |||
407 | init_waitqueue_head(&priv->alarm_wq); | 406 | init_waitqueue_head(&priv->alarm_wq); |
408 | 407 | ||
409 | /* link it into our alarmlist */ | 408 | /* link it into our alarmlist */ |
410 | spin_lock_irq(&alarm_lock); | 409 | spin_lock_irq(&gpio_lock); |
411 | priv->next = alarmlist; | 410 | priv->next = alarmlist; |
412 | alarmlist = priv; | 411 | alarmlist = priv; |
413 | spin_unlock_irq(&alarm_lock); | 412 | spin_unlock_irq(&gpio_lock); |
414 | } | 413 | } |
415 | 414 | ||
416 | return 0; | 415 | return 0; |
417 | } | 416 | } |
418 | 417 | ||
419 | static int | 418 | static int gpio_release(struct inode *inode, struct file *filp) |
420 | gpio_release(struct inode *inode, struct file *filp) | ||
421 | { | 419 | { |
422 | struct gpio_private *p; | 420 | struct gpio_private *p; |
423 | struct gpio_private *todel; | 421 | struct gpio_private *todel; |
@@ -425,11 +423,11 @@ gpio_release(struct inode *inode, struct file *filp) | |||
425 | unsigned long a_high, a_low; | 423 | unsigned long a_high, a_low; |
426 | 424 | ||
427 | /* prepare to free private structure */ | 425 | /* prepare to free private structure */ |
428 | todel = (struct gpio_private *)filp->private_data; | 426 | todel = filp->private_data; |
429 | 427 | ||
430 | /* unlink from alarmlist - only for non-PWM ports though */ | 428 | /* unlink from alarmlist - only for non-PWM ports though */ |
431 | if (todel->minor <= GPIO_MINOR_LAST) { | 429 | if (todel->minor <= GPIO_MINOR_LAST) { |
432 | spin_lock_irq(&alarm_lock); | 430 | spin_lock_irq(&gpio_lock); |
433 | p = alarmlist; | 431 | p = alarmlist; |
434 | 432 | ||
435 | if (p == todel) | 433 | if (p == todel) |
@@ -463,7 +461,7 @@ gpio_release(struct inode *inode, struct file *filp) | |||
463 | a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | 461 | a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); |
464 | #endif | 462 | #endif |
465 | 463 | ||
466 | spin_unlock_irq(&alarm_lock); | 464 | spin_unlock_irq(&gpio_lock); |
467 | } | 465 | } |
468 | kfree(todel); | 466 | kfree(todel); |
469 | 467 | ||
@@ -482,11 +480,13 @@ inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) | |||
482 | unsigned long flags; | 480 | unsigned long flags; |
483 | unsigned long dir_shadow; | 481 | unsigned long dir_shadow; |
484 | 482 | ||
485 | local_irq_save(flags); | 483 | spin_lock_irqsave(&gpio_lock, flags); |
486 | dir_shadow = *dir_oe[priv->minor]; | 484 | |
487 | dir_shadow &= ~(arg & changeable_dir[priv->minor]); | 485 | dir_shadow = readl(dir_oe[priv->minor]) & |
488 | *dir_oe[priv->minor] = dir_shadow; | 486 | ~(arg & changeable_dir[priv->minor]); |
489 | local_irq_restore(flags); | 487 | writel(dir_shadow, dir_oe[priv->minor]); |
488 | |||
489 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
490 | 490 | ||
491 | if (priv->minor == GPIO_MINOR_C) | 491 | if (priv->minor == GPIO_MINOR_C) |
492 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | 492 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ |
@@ -501,36 +501,32 @@ inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) | |||
501 | 501 | ||
502 | } /* setget_input */ | 502 | } /* setget_input */ |
503 | 503 | ||
504 | inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg) | 504 | static inline unsigned long setget_output(struct gpio_private *priv, |
505 | unsigned long arg) | ||
505 | { | 506 | { |
506 | unsigned long flags; | 507 | unsigned long flags; |
507 | unsigned long dir_shadow; | 508 | unsigned long dir_shadow; |
508 | 509 | ||
509 | local_irq_save(flags); | 510 | spin_lock_irqsave(&gpio_lock, flags); |
510 | dir_shadow = *dir_oe[priv->minor]; | ||
511 | dir_shadow |= (arg & changeable_dir[priv->minor]); | ||
512 | *dir_oe[priv->minor] = dir_shadow; | ||
513 | local_irq_restore(flags); | ||
514 | return dir_shadow; | ||
515 | } /* setget_output */ | ||
516 | 511 | ||
517 | static int | 512 | dir_shadow = readl(dir_oe[priv->minor]) | |
518 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg); | 513 | (arg & changeable_dir[priv->minor]); |
514 | writel(dir_shadow, dir_oe[priv->minor]); | ||
519 | 515 | ||
520 | static int | 516 | spin_unlock_irqrestore(&gpio_lock, flags); |
521 | gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, unsigned long arg); | 517 | return dir_shadow; |
518 | } /* setget_output */ | ||
522 | 519 | ||
523 | static int | 520 | static int gpio_ioctl(struct inode *inode, struct file *file, |
524 | gpio_ioctl(struct inode *inode, struct file *file, | 521 | unsigned int cmd, unsigned long arg) |
525 | unsigned int cmd, unsigned long arg) | ||
526 | { | 522 | { |
527 | unsigned long flags; | 523 | unsigned long flags; |
528 | unsigned long val; | 524 | unsigned long val; |
529 | unsigned long shadow; | 525 | unsigned long shadow; |
530 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 526 | struct gpio_private *priv = file->private_data; |
531 | 527 | ||
532 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) | 528 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) |
533 | return -EINVAL; | 529 | return -ENOTTY; |
534 | 530 | ||
535 | /* Check for special ioctl handlers first */ | 531 | /* Check for special ioctl handlers first */ |
536 | 532 | ||
@@ -549,23 +545,22 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
549 | switch (_IOC_NR(cmd)) { | 545 | switch (_IOC_NR(cmd)) { |
550 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | 546 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ |
551 | /* Read the port. */ | 547 | /* Read the port. */ |
552 | return *data_in[priv->minor]; | 548 | return readl(data_in[priv->minor]); |
553 | break; | ||
554 | case IO_SETBITS: | 549 | case IO_SETBITS: |
555 | local_irq_save(flags); | 550 | spin_lock_irqsave(&gpio_lock, flags); |
556 | /* Set changeable bits with a 1 in arg. */ | 551 | /* Set changeable bits with a 1 in arg. */ |
557 | shadow = *data_out[priv->minor]; | 552 | shadow = readl(data_out[priv->minor]) | |
558 | shadow |= (arg & changeable_bits[priv->minor]); | 553 | (arg & changeable_bits[priv->minor]); |
559 | *data_out[priv->minor] = shadow; | 554 | writel(shadow, data_out[priv->minor]); |
560 | local_irq_restore(flags); | 555 | spin_unlock_irqrestore(&gpio_lock, flags); |
561 | break; | 556 | break; |
562 | case IO_CLRBITS: | 557 | case IO_CLRBITS: |
563 | local_irq_save(flags); | 558 | spin_lock_irqsave(&gpio_lock, flags); |
564 | /* Clear changeable bits with a 1 in arg. */ | 559 | /* Clear changeable bits with a 1 in arg. */ |
565 | shadow = *data_out[priv->minor]; | 560 | shadow = readl(data_out[priv->minor]) & |
566 | shadow &= ~(arg & changeable_bits[priv->minor]); | 561 | ~(arg & changeable_bits[priv->minor]); |
567 | *data_out[priv->minor] = shadow; | 562 | writel(shadow, data_out[priv->minor]); |
568 | local_irq_restore(flags); | 563 | spin_unlock_irqrestore(&gpio_lock, flags); |
569 | break; | 564 | break; |
570 | case IO_HIGHALARM: | 565 | case IO_HIGHALARM: |
571 | /* Set alarm when bits with 1 in arg go high. */ | 566 | /* Set alarm when bits with 1 in arg go high. */ |
@@ -585,13 +580,14 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
585 | break; | 580 | break; |
586 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | 581 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ |
587 | /* Read direction 0=input 1=output */ | 582 | /* Read direction 0=input 1=output */ |
588 | return *dir_oe[priv->minor]; | 583 | return readl(dir_oe[priv->minor]); |
584 | |||
589 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ | 585 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ |
590 | /* Set direction 0=unchanged 1=input, | 586 | /* Set direction 0=unchanged 1=input, |
591 | * return mask with 1=input | 587 | * return mask with 1=input |
592 | */ | 588 | */ |
593 | return setget_input(priv, arg); | 589 | return setget_input(priv, arg); |
594 | break; | 590 | |
595 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ | 591 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ |
596 | /* Set direction 0=unchanged 1=output, | 592 | /* Set direction 0=unchanged 1=output, |
597 | * return mask with 1=output | 593 | * return mask with 1=output |
@@ -600,56 +596,61 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
600 | 596 | ||
601 | case IO_CFG_WRITE_MODE: | 597 | case IO_CFG_WRITE_MODE: |
602 | { | 598 | { |
603 | unsigned long dir_shadow; | 599 | int res = -EPERM; |
604 | dir_shadow = *dir_oe[priv->minor]; | 600 | unsigned long dir_shadow, clk_mask, data_mask, write_msb; |
601 | |||
602 | clk_mask = arg & 0xFF; | ||
603 | data_mask = (arg >> 8) & 0xFF; | ||
604 | write_msb = (arg >> 16) & 0x01; | ||
605 | 605 | ||
606 | priv->clk_mask = arg & 0xFF; | ||
607 | priv->data_mask = (arg >> 8) & 0xFF; | ||
608 | priv->write_msb = (arg >> 16) & 0x01; | ||
609 | /* Check if we're allowed to change the bits and | 606 | /* Check if we're allowed to change the bits and |
610 | * the direction is correct | 607 | * the direction is correct |
611 | */ | 608 | */ |
612 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && | 609 | spin_lock_irqsave(&gpio_lock, flags); |
613 | (priv->data_mask & changeable_bits[priv->minor]) && | 610 | dir_shadow = readl(dir_oe[priv->minor]); |
614 | (priv->clk_mask & dir_shadow) && | 611 | if ((clk_mask & changeable_bits[priv->minor]) && |
615 | (priv->data_mask & dir_shadow))) { | 612 | (data_mask & changeable_bits[priv->minor]) && |
616 | priv->clk_mask = 0; | 613 | (clk_mask & dir_shadow) && |
617 | priv->data_mask = 0; | 614 | (data_mask & dir_shadow)) { |
618 | return -EPERM; | 615 | priv->clk_mask = clk_mask; |
616 | priv->data_mask = data_mask; | ||
617 | priv->write_msb = write_msb; | ||
618 | res = 0; | ||
619 | } | 619 | } |
620 | break; | 620 | spin_unlock_irqrestore(&gpio_lock, flags); |
621 | |||
622 | return res; | ||
621 | } | 623 | } |
622 | case IO_READ_INBITS: | 624 | case IO_READ_INBITS: |
623 | /* *arg is result of reading the input pins */ | 625 | /* *arg is result of reading the input pins */ |
624 | val = *data_in[priv->minor]; | 626 | val = readl(data_in[priv->minor]); |
625 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 627 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
626 | return -EFAULT; | 628 | return -EFAULT; |
627 | return 0; | 629 | return 0; |
628 | break; | ||
629 | case IO_READ_OUTBITS: | 630 | case IO_READ_OUTBITS: |
630 | /* *arg is result of reading the output shadow */ | 631 | /* *arg is result of reading the output shadow */ |
631 | val = *data_out[priv->minor]; | 632 | val = *data_out[priv->minor]; |
632 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 633 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
633 | return -EFAULT; | 634 | return -EFAULT; |
634 | break; | 635 | break; |
635 | case IO_SETGET_INPUT: | 636 | case IO_SETGET_INPUT: |
636 | /* bits set in *arg is set to input, | 637 | /* bits set in *arg is set to input, |
637 | * *arg updated with current input pins. | 638 | * *arg updated with current input pins. |
638 | */ | 639 | */ |
639 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | 640 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
640 | return -EFAULT; | 641 | return -EFAULT; |
641 | val = setget_input(priv, val); | 642 | val = setget_input(priv, val); |
642 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 643 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
643 | return -EFAULT; | 644 | return -EFAULT; |
644 | break; | 645 | break; |
645 | case IO_SETGET_OUTPUT: | 646 | case IO_SETGET_OUTPUT: |
646 | /* bits set in *arg is set to output, | 647 | /* bits set in *arg is set to output, |
647 | * *arg updated with current output pins. | 648 | * *arg updated with current output pins. |
648 | */ | 649 | */ |
649 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | 650 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
650 | return -EFAULT; | 651 | return -EFAULT; |
651 | val = setget_output(priv, val); | 652 | val = setget_output(priv, val); |
652 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 653 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
653 | return -EFAULT; | 654 | return -EFAULT; |
654 | break; | 655 | break; |
655 | default: | 656 | default: |
@@ -660,32 +661,32 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
660 | } | 661 | } |
661 | 662 | ||
662 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | 663 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
663 | static int | 664 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, |
664 | virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 665 | unsigned long arg) |
665 | { | 666 | { |
666 | unsigned long flags; | 667 | unsigned long flags; |
667 | unsigned short val; | 668 | unsigned short val; |
668 | unsigned short shadow; | 669 | unsigned short shadow; |
669 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 670 | struct gpio_private *priv = file->private_data; |
670 | 671 | ||
671 | switch (_IOC_NR(cmd)) { | 672 | switch (_IOC_NR(cmd)) { |
672 | case IO_SETBITS: | 673 | case IO_SETBITS: |
673 | local_irq_save(flags); | 674 | spin_lock_irqsave(&gpio_lock, flags); |
674 | /* Set changeable bits with a 1 in arg. */ | 675 | /* Set changeable bits with a 1 in arg. */ |
675 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | 676 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
676 | shadow |= ~*dir_oe[priv->minor]; | 677 | shadow |= ~readl(dir_oe[priv->minor]) | |
677 | shadow |= (arg & changeable_bits[priv->minor]); | 678 | (arg & changeable_bits[priv->minor]); |
678 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | 679 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
679 | local_irq_restore(flags); | 680 | spin_lock_irqrestore(&gpio_lock, flags); |
680 | break; | 681 | break; |
681 | case IO_CLRBITS: | 682 | case IO_CLRBITS: |
682 | local_irq_save(flags); | 683 | spin_lock_irqsave(&gpio_lock, flags); |
683 | /* Clear changeable bits with a 1 in arg. */ | 684 | /* Clear changeable bits with a 1 in arg. */ |
684 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | 685 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
685 | shadow |= ~*dir_oe[priv->minor]; | 686 | shadow |= ~readl(dir_oe[priv->minor]) & |
686 | shadow &= ~(arg & changeable_bits[priv->minor]); | 687 | ~(arg & changeable_bits[priv->minor]); |
687 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | 688 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
688 | local_irq_restore(flags); | 689 | spin_lock_irqrestore(&gpio_lock, flags); |
689 | break; | 690 | break; |
690 | case IO_HIGHALARM: | 691 | case IO_HIGHALARM: |
691 | /* Set alarm when bits with 1 in arg go high. */ | 692 | /* Set alarm when bits with 1 in arg go high. */ |
@@ -703,7 +704,7 @@ virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
703 | case IO_CFG_WRITE_MODE: | 704 | case IO_CFG_WRITE_MODE: |
704 | { | 705 | { |
705 | unsigned long dir_shadow; | 706 | unsigned long dir_shadow; |
706 | dir_shadow = *dir_oe[priv->minor]; | 707 | dir_shadow = readl(dir_oe[priv->minor]); |
707 | 708 | ||
708 | priv->clk_mask = arg & 0xFF; | 709 | priv->clk_mask = arg & 0xFF; |
709 | priv->data_mask = (arg >> 8) & 0xFF; | 710 | priv->data_mask = (arg >> 8) & 0xFF; |
@@ -723,17 +724,16 @@ virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
723 | } | 724 | } |
724 | case IO_READ_INBITS: | 725 | case IO_READ_INBITS: |
725 | /* *arg is result of reading the input pins */ | 726 | /* *arg is result of reading the input pins */ |
726 | val = cached_virtual_gpio_read; | 727 | val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]); |
727 | val &= ~*dir_oe[priv->minor]; | 728 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
728 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | ||
729 | return -EFAULT; | 729 | return -EFAULT; |
730 | return 0; | 730 | return 0; |
731 | break; | 731 | |
732 | case IO_READ_OUTBITS: | 732 | case IO_READ_OUTBITS: |
733 | /* *arg is result of reading the output shadow */ | 733 | /* *arg is result of reading the output shadow */ |
734 | i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); | 734 | i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); |
735 | val &= *dir_oe[priv->minor]; | 735 | val &= readl(dir_oe[priv->minor]); |
736 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 736 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
737 | return -EFAULT; | 737 | return -EFAULT; |
738 | break; | 738 | break; |
739 | case IO_SETGET_INPUT: | 739 | case IO_SETGET_INPUT: |
@@ -741,11 +741,11 @@ virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
741 | /* bits set in *arg is set to input, | 741 | /* bits set in *arg is set to input, |
742 | * *arg updated with current input pins. | 742 | * *arg updated with current input pins. |
743 | */ | 743 | */ |
744 | unsigned short input_mask = ~*dir_oe[priv->minor]; | 744 | unsigned short input_mask = ~readl(dir_oe[priv->minor]); |
745 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | 745 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
746 | return -EFAULT; | 746 | return -EFAULT; |
747 | val = setget_input(priv, val); | 747 | val = setget_input(priv, val); |
748 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 748 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
749 | return -EFAULT; | 749 | return -EFAULT; |
750 | if ((input_mask & val) != input_mask) { | 750 | if ((input_mask & val) != input_mask) { |
751 | /* Input pins changed. All ports desired as input | 751 | /* Input pins changed. All ports desired as input |
@@ -765,10 +765,10 @@ virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
765 | /* bits set in *arg is set to output, | 765 | /* bits set in *arg is set to output, |
766 | * *arg updated with current output pins. | 766 | * *arg updated with current output pins. |
767 | */ | 767 | */ |
768 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | 768 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
769 | return -EFAULT; | 769 | return -EFAULT; |
770 | val = setget_output(priv, val); | 770 | val = setget_output(priv, val); |
771 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | 771 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
772 | return -EFAULT; | 772 | return -EFAULT; |
773 | break; | 773 | break; |
774 | default: | 774 | default: |
@@ -778,8 +778,7 @@ virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
778 | } | 778 | } |
779 | #endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ | 779 | #endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ |
780 | 780 | ||
781 | static int | 781 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg) |
782 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | ||
783 | { | 782 | { |
784 | unsigned char green; | 783 | unsigned char green; |
785 | unsigned char red; | 784 | unsigned char red; |
@@ -829,8 +828,7 @@ static int gpio_pwm_set_period(unsigned long arg, int pwm_port) | |||
829 | struct io_pwm_set_period periods; | 828 | struct io_pwm_set_period periods; |
830 | reg_gio_rw_pwm0_var rw_pwm_widths; | 829 | reg_gio_rw_pwm0_var rw_pwm_widths; |
831 | 830 | ||
832 | if (copy_from_user(&periods, (struct io_pwm_set_period *) arg, | 831 | if (copy_from_user(&periods, (void __user *)arg, sizeof(periods))) |
833 | sizeof(periods))) | ||
834 | return -EFAULT; | 832 | return -EFAULT; |
835 | if (periods.lo > 8191 || periods.hi > 8191) | 833 | if (periods.lo > 8191 || periods.hi > 8191) |
836 | return -EINVAL; | 834 | return -EINVAL; |
@@ -856,8 +854,8 @@ static int gpio_pwm_set_duty(unsigned long arg, int pwm_port) | |||
856 | return 0; | 854 | return 0; |
857 | } | 855 | } |
858 | 856 | ||
859 | static int | 857 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, |
860 | gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, unsigned long arg) | 858 | unsigned long arg) |
861 | { | 859 | { |
862 | int pwm_port = priv->minor - GPIO_MINOR_PWM0; | 860 | int pwm_port = priv->minor - GPIO_MINOR_PWM0; |
863 | 861 | ||
@@ -874,7 +872,7 @@ gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, unsigned long arg) | |||
874 | return 0; | 872 | return 0; |
875 | } | 873 | } |
876 | 874 | ||
877 | struct file_operations gpio_fops = { | 875 | static const struct file_operations gpio_fops = { |
878 | .owner = THIS_MODULE, | 876 | .owner = THIS_MODULE, |
879 | .poll = gpio_poll, | 877 | .poll = gpio_poll, |
880 | .ioctl = gpio_ioctl, | 878 | .ioctl = gpio_ioctl, |
@@ -884,8 +882,7 @@ struct file_operations gpio_fops = { | |||
884 | }; | 882 | }; |
885 | 883 | ||
886 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | 884 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
887 | static void | 885 | static void __init virtual_gpio_init(void) |
888 | virtual_gpio_init(void) | ||
889 | { | 886 | { |
890 | reg_gio_rw_intr_cfg intr_cfg; | 887 | reg_gio_rw_intr_cfg intr_cfg; |
891 | reg_gio_rw_intr_mask intr_mask; | 888 | reg_gio_rw_intr_mask intr_mask; |
@@ -943,11 +940,13 @@ virtual_gpio_init(void) | |||
943 | 940 | ||
944 | /* main driver initialization routine, called from mem.c */ | 941 | /* main driver initialization routine, called from mem.c */ |
945 | 942 | ||
946 | static __init int | 943 | static int __init gpio_init(void) |
947 | gpio_init(void) | ||
948 | { | 944 | { |
949 | int res; | 945 | int res; |
950 | 946 | ||
947 | printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 " | ||
948 | "Axis Communications AB\n"); | ||
949 | |||
951 | /* do the formalities */ | 950 | /* do the formalities */ |
952 | 951 | ||
953 | res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); | 952 | res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); |
@@ -963,11 +962,12 @@ gpio_init(void) | |||
963 | CRIS_LED_DISK_READ(0); | 962 | CRIS_LED_DISK_READ(0); |
964 | CRIS_LED_DISK_WRITE(0); | 963 | CRIS_LED_DISK_WRITE(0); |
965 | 964 | ||
966 | printk(KERN_INFO "ETRAX FS GPIO driver v2.6, (c) 2003-2007 " | 965 | int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, |
967 | "Axis Communications AB\n"); | 966 | IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist); |
968 | if (request_irq(GIO_INTR_VECT, gpio_interrupt, | 967 | if (res2) { |
969 | IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist)) | ||
970 | printk(KERN_ERR "err: irq for gpio\n"); | 968 | printk(KERN_ERR "err: irq for gpio\n"); |
969 | return res2; | ||
970 | } | ||
971 | 971 | ||
972 | /* No IRQs by default. */ | 972 | /* No IRQs by default. */ |
973 | REG_WR_INT(gio, regi_gio, rw_intr_pins, 0); | 973 | REG_WR_INT(gio, regi_gio, rw_intr_pins, 0); |