it8761e_gpio.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * it8761_gpio.c - GPIO interface for IT8761E Super I/O chip
  3. *
  4. * Author: Denis Turischev <denis@compulab.co.il>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License 2 as published
  8. * by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; see the file COPYING. If not, write to
  17. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/io.h>
  23. #include <linux/errno.h>
  24. #include <linux/ioport.h>
  25. #include <linux/gpio.h>
  26. #define SIO_CHIP_ID 0x8761
  27. #define CHIP_ID_HIGH_BYTE 0x20
  28. #define CHIP_ID_LOW_BYTE 0x21
  29. static u8 ports[2] = { 0x2e, 0x4e };
  30. static u8 port;
  31. static DEFINE_SPINLOCK(sio_lock);
  32. #define GPIO_NAME "it8761-gpio"
  33. #define GPIO_BA_HIGH_BYTE 0x60
  34. #define GPIO_BA_LOW_BYTE 0x61
  35. #define GPIO_IOSIZE 4
  36. #define GPIO1X_IO 0xf0
  37. #define GPIO2X_IO 0xf1
  38. static u16 gpio_ba;
  39. static u8 read_reg(u8 addr, u8 port)
  40. {
  41. outb(addr, port);
  42. return inb(port + 1);
  43. }
  44. static void write_reg(u8 data, u8 addr, u8 port)
  45. {
  46. outb(addr, port);
  47. outb(data, port + 1);
  48. }
  49. static void enter_conf_mode(u8 port)
  50. {
  51. outb(0x87, port);
  52. outb(0x61, port);
  53. outb(0x55, port);
  54. outb((port == 0x2e) ? 0x55 : 0xaa, port);
  55. }
  56. static void exit_conf_mode(u8 port)
  57. {
  58. outb(0x2, port);
  59. outb(0x2, port + 1);
  60. }
  61. static void enter_gpio_mode(u8 port)
  62. {
  63. write_reg(0x2, 0x7, port);
  64. }
  65. static int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
  66. {
  67. u16 reg;
  68. u8 bit;
  69. bit = gpio_num % 8;
  70. reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
  71. return !!(inb(reg) & (1 << bit));
  72. }
  73. static int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
  74. {
  75. u8 curr_dirs;
  76. u8 io_reg, bit;
  77. bit = gpio_num % 8;
  78. io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
  79. spin_lock(&sio_lock);
  80. enter_conf_mode(port);
  81. enter_gpio_mode(port);
  82. curr_dirs = read_reg(io_reg, port);
  83. if (curr_dirs & (1 << bit))
  84. write_reg(curr_dirs & ~(1 << bit), io_reg, port);
  85. exit_conf_mode(port);
  86. spin_unlock(&sio_lock);
  87. return 0;
  88. }
  89. static void it8761e_gpio_set(struct gpio_chip *gc,
  90. unsigned gpio_num, int val)
  91. {
  92. u8 curr_vals, bit;
  93. u16 reg;
  94. bit = gpio_num % 8;
  95. reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
  96. spin_lock(&sio_lock);
  97. curr_vals = inb(reg);
  98. if (val)
  99. outb(curr_vals | (1 << bit) , reg);
  100. else
  101. outb(curr_vals & ~(1 << bit), reg);
  102. spin_unlock(&sio_lock);
  103. }
  104. static int it8761e_gpio_direction_out(struct gpio_chip *gc,
  105. unsigned gpio_num, int val)
  106. {
  107. u8 curr_dirs, io_reg, bit;
  108. bit = gpio_num % 8;
  109. io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
  110. it8761e_gpio_set(gc, gpio_num, val);
  111. spin_lock(&sio_lock);
  112. enter_conf_mode(port);
  113. enter_gpio_mode(port);
  114. curr_dirs = read_reg(io_reg, port);
  115. if (!(curr_dirs & (1 << bit)))
  116. write_reg(curr_dirs | (1 << bit), io_reg, port);
  117. exit_conf_mode(port);
  118. spin_unlock(&sio_lock);
  119. return 0;
  120. }
  121. static struct gpio_chip it8761e_gpio_chip = {
  122. .label = GPIO_NAME,
  123. .owner = THIS_MODULE,
  124. .get = it8761e_gpio_get,
  125. .direction_input = it8761e_gpio_direction_in,
  126. .set = it8761e_gpio_set,
  127. .direction_output = it8761e_gpio_direction_out,
  128. };
  129. static int __init it8761e_gpio_init(void)
  130. {
  131. int i, id, err;
  132. /* chip and port detection */
  133. for (i = 0; i < ARRAY_SIZE(ports); i++) {
  134. spin_lock(&sio_lock);
  135. enter_conf_mode(ports[i]);
  136. id = (read_reg(CHIP_ID_HIGH_BYTE, ports[i]) << 8) +
  137. read_reg(CHIP_ID_LOW_BYTE, ports[i]);
  138. exit_conf_mode(ports[i]);
  139. spin_unlock(&sio_lock);
  140. if (id == SIO_CHIP_ID) {
  141. port = ports[i];
  142. break;
  143. }
  144. }
  145. if (!port)
  146. return -ENODEV;
  147. /* fetch GPIO base address */
  148. enter_conf_mode(port);
  149. enter_gpio_mode(port);
  150. gpio_ba = (read_reg(GPIO_BA_HIGH_BYTE, port) << 8) +
  151. read_reg(GPIO_BA_LOW_BYTE, port);
  152. exit_conf_mode(port);
  153. if (!request_region(gpio_ba, GPIO_IOSIZE, GPIO_NAME))
  154. return -EBUSY;
  155. it8761e_gpio_chip.base = -1;
  156. it8761e_gpio_chip.ngpio = 16;
  157. err = gpiochip_add(&it8761e_gpio_chip);
  158. if (err < 0)
  159. goto gpiochip_add_err;
  160. return 0;
  161. gpiochip_add_err:
  162. release_region(gpio_ba, GPIO_IOSIZE);
  163. gpio_ba = 0;
  164. return err;
  165. }
  166. static void __exit it8761e_gpio_exit(void)
  167. {
  168. if (gpio_ba) {
  169. int ret = gpiochip_remove(&it8761e_gpio_chip);
  170. WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
  171. __func__, ret);
  172. release_region(gpio_ba, GPIO_IOSIZE);
  173. gpio_ba = 0;
  174. }
  175. }
  176. module_init(it8761e_gpio_init);
  177. module_exit(it8761e_gpio_exit);
  178. MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
  179. MODULE_DESCRIPTION("GPIO interface for IT8761E Super I/O chip");
  180. MODULE_LICENSE("GPL");