gpio.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * $Id: gpio.c,v 1.4 2003/05/19 22:24:18 lethal Exp $
  3. * by Greg Banks <gbanks@pocketpenguins.com>
  4. * (c) 2000 PocketPenguins Inc
  5. *
  6. * GPIO pin support for HD64465 companion chip.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/module.h>
  11. #include <linux/sched.h>
  12. #include <linux/ioport.h>
  13. #include <asm/io.h>
  14. #include <asm/hd64465/gpio.h>
  15. #define _PORTOF(portpin) (((portpin)>>3)&0x7)
  16. #define _PINOF(portpin) ((portpin)&0x7)
  17. /* Register addresses parametrised on port */
  18. #define GPIO_CR(port) (HD64465_REG_GPACR+((port)<<1))
  19. #define GPIO_DR(port) (HD64465_REG_GPADR+((port)<<1))
  20. #define GPIO_ICR(port) (HD64465_REG_GPAICR+((port)<<1))
  21. #define GPIO_ISR(port) (HD64465_REG_GPAISR+((port)<<1))
  22. #define GPIO_NPORTS 5
  23. #define MODNAME "hd64465_gpio"
  24. EXPORT_SYMBOL(hd64465_gpio_configure);
  25. EXPORT_SYMBOL(hd64465_gpio_get_pin);
  26. EXPORT_SYMBOL(hd64465_gpio_get_port);
  27. EXPORT_SYMBOL(hd64465_gpio_register_irq);
  28. EXPORT_SYMBOL(hd64465_gpio_set_pin);
  29. EXPORT_SYMBOL(hd64465_gpio_set_port);
  30. EXPORT_SYMBOL(hd64465_gpio_unregister_irq);
  31. /* TODO: each port should be protected with a spinlock */
  32. void hd64465_gpio_configure(int portpin, int direction)
  33. {
  34. unsigned short cr;
  35. unsigned int shift = (_PINOF(portpin)<<1);
  36. cr = inw(GPIO_CR(_PORTOF(portpin)));
  37. cr &= ~(3<<shift);
  38. cr |= direction<<shift;
  39. outw(cr, GPIO_CR(_PORTOF(portpin)));
  40. }
  41. void hd64465_gpio_set_pin(int portpin, unsigned int value)
  42. {
  43. unsigned short d;
  44. unsigned short mask = 1<<(_PINOF(portpin));
  45. d = inw(GPIO_DR(_PORTOF(portpin)));
  46. if (value)
  47. d |= mask;
  48. else
  49. d &= ~mask;
  50. outw(d, GPIO_DR(_PORTOF(portpin)));
  51. }
  52. unsigned int hd64465_gpio_get_pin(int portpin)
  53. {
  54. return inw(GPIO_DR(_PORTOF(portpin))) & (1<<(_PINOF(portpin)));
  55. }
  56. /* TODO: for cleaner atomicity semantics, add a mask to this routine */
  57. void hd64465_gpio_set_port(int port, unsigned int value)
  58. {
  59. outw(value, GPIO_DR(port));
  60. }
  61. unsigned int hd64465_gpio_get_port(int port)
  62. {
  63. return inw(GPIO_DR(port));
  64. }
  65. static struct {
  66. void (*func)(int portpin, void *dev);
  67. void *dev;
  68. } handlers[GPIO_NPORTS * 8];
  69. static irqreturn_t hd64465_gpio_interrupt(int irq, void *dev)
  70. {
  71. unsigned short port, pin, isr, mask, portpin;
  72. for (port=0 ; port<GPIO_NPORTS ; port++) {
  73. isr = inw(GPIO_ISR(port));
  74. for (pin=0 ; pin<8 ; pin++) {
  75. mask = 1<<pin;
  76. if (isr & mask) {
  77. portpin = (port<<3)|pin;
  78. if (handlers[portpin].func != 0)
  79. handlers[portpin].func(portpin, handlers[portpin].dev);
  80. else
  81. printk(KERN_NOTICE "unexpected GPIO interrupt, pin %c%d\n",
  82. port+'A', (int)pin);
  83. }
  84. }
  85. /* Write 1s back to ISR to clear it? That's what the manual says.. */
  86. outw(isr, GPIO_ISR(port));
  87. }
  88. return IRQ_HANDLED;
  89. }
  90. void hd64465_gpio_register_irq(int portpin, int mode,
  91. void (*handler)(int portpin, void *dev), void *dev)
  92. {
  93. unsigned long flags;
  94. unsigned short icr, mask;
  95. if (handler == 0)
  96. return;
  97. local_irq_save(flags);
  98. handlers[portpin].func = handler;
  99. handlers[portpin].dev = dev;
  100. /*
  101. * Configure Interrupt Control Register
  102. */
  103. icr = inw(GPIO_ICR(_PORTOF(portpin)));
  104. mask = (1<<_PINOF(portpin));
  105. /* unmask interrupt */
  106. icr &= ~mask;
  107. /* set TS bit */
  108. mask <<= 8;
  109. icr &= ~mask;
  110. if (mode == HD64465_GPIO_RISING)
  111. icr |= mask;
  112. outw(icr, GPIO_ICR(_PORTOF(portpin)));
  113. local_irq_restore(flags);
  114. }
  115. void hd64465_gpio_unregister_irq(int portpin)
  116. {
  117. unsigned long flags;
  118. unsigned short icr;
  119. local_irq_save(flags);
  120. /*
  121. * Configure Interrupt Control Register
  122. */
  123. icr = inw(GPIO_ICR(_PORTOF(portpin)));
  124. icr |= (1<<_PINOF(portpin)); /* mask interrupt */
  125. outw(icr, GPIO_ICR(_PORTOF(portpin)));
  126. handlers[portpin].func = 0;
  127. handlers[portpin].dev = 0;
  128. local_irq_restore(flags);
  129. }
  130. static int __init hd64465_gpio_init(void)
  131. {
  132. if (!request_region(HD64465_REG_GPACR, 0x1000, MODNAME))
  133. return -EBUSY;
  134. if (request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt,
  135. IRQF_DISABLED, MODNAME, 0))
  136. goto out_irqfailed;
  137. printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO);
  138. return 0;
  139. out_irqfailed:
  140. release_region(HD64465_REG_GPACR, 0x1000);
  141. return -EINVAL;
  142. }
  143. static void __exit hd64465_gpio_exit(void)
  144. {
  145. release_region(HD64465_REG_GPACR, 0x1000);
  146. free_irq(HD64465_IRQ_GPIO, 0);
  147. }
  148. module_init(hd64465_gpio_init);
  149. module_exit(hd64465_gpio_exit);
  150. MODULE_LICENSE("GPL");