gpio-gpio-mm.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * GPIO driver for the Diamond Systems GPIO-MM
  3. * Copyright (C) 2016 William Breathitt Gray
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License, version 2, as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * This driver supports the following Diamond Systems devices: GPIO-MM and
  15. * GPIO-MM-12.
  16. */
  17. #include <linux/bitops.h>
  18. #include <linux/device.h>
  19. #include <linux/errno.h>
  20. #include <linux/gpio/driver.h>
  21. #include <linux/io.h>
  22. #include <linux/ioport.h>
  23. #include <linux/isa.h>
  24. #include <linux/kernel.h>
  25. #include <linux/module.h>
  26. #include <linux/moduleparam.h>
  27. #include <linux/spinlock.h>
  28. #define GPIOMM_EXTENT 8
  29. #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
  30. static unsigned int base[MAX_NUM_GPIOMM];
  31. static unsigned int num_gpiomm;
  32. module_param_array(base, uint, &num_gpiomm, 0);
  33. MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
  34. /**
  35. * struct gpiomm_gpio - GPIO device private data structure
  36. * @chip: instance of the gpio_chip
  37. * @io_state: bit I/O state (whether bit is set to input or output)
  38. * @out_state: output bits state
  39. * @control: Control registers state
  40. * @lock: synchronization lock to prevent I/O race conditions
  41. * @base: base port address of the GPIO device
  42. */
  43. struct gpiomm_gpio {
  44. struct gpio_chip chip;
  45. unsigned char io_state[6];
  46. unsigned char out_state[6];
  47. unsigned char control[2];
  48. spinlock_t lock;
  49. unsigned int base;
  50. };
  51. static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
  52. unsigned int offset)
  53. {
  54. struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
  55. const unsigned int port = offset / 8;
  56. const unsigned int mask = BIT(offset % 8);
  57. return !!(gpiommgpio->io_state[port] & mask);
  58. }
  59. static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
  60. unsigned int offset)
  61. {
  62. struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
  63. const unsigned int io_port = offset / 8;
  64. const unsigned int control_port = io_port / 3;
  65. const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
  66. unsigned long flags;
  67. unsigned int control;
  68. spin_lock_irqsave(&gpiommgpio->lock, flags);
  69. /* Check if configuring Port C */
  70. if (io_port == 2 || io_port == 5) {
  71. /* Port C can be configured by nibble */
  72. if (offset % 8 > 3) {
  73. gpiommgpio->io_state[io_port] |= 0xF0;
  74. gpiommgpio->control[control_port] |= BIT(3);
  75. } else {
  76. gpiommgpio->io_state[io_port] |= 0x0F;
  77. gpiommgpio->control[control_port] |= BIT(0);
  78. }
  79. } else {
  80. gpiommgpio->io_state[io_port] |= 0xFF;
  81. if (io_port == 0 || io_port == 3)
  82. gpiommgpio->control[control_port] |= BIT(4);
  83. else
  84. gpiommgpio->control[control_port] |= BIT(1);
  85. }
  86. control = BIT(7) | gpiommgpio->control[control_port];
  87. outb(control, control_addr);
  88. spin_unlock_irqrestore(&gpiommgpio->lock, flags);
  89. return 0;
  90. }
  91. static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
  92. unsigned int offset, int value)
  93. {
  94. struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
  95. const unsigned int io_port = offset / 8;
  96. const unsigned int control_port = io_port / 3;
  97. const unsigned int mask = BIT(offset % 8);
  98. const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
  99. const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
  100. unsigned long flags;
  101. unsigned int control;
  102. spin_lock_irqsave(&gpiommgpio->lock, flags);
  103. /* Check if configuring Port C */
  104. if (io_port == 2 || io_port == 5) {
  105. /* Port C can be configured by nibble */
  106. if (offset % 8 > 3) {
  107. gpiommgpio->io_state[io_port] &= 0x0F;
  108. gpiommgpio->control[control_port] &= ~BIT(3);
  109. } else {
  110. gpiommgpio->io_state[io_port] &= 0xF0;
  111. gpiommgpio->control[control_port] &= ~BIT(0);
  112. }
  113. } else {
  114. gpiommgpio->io_state[io_port] &= 0x00;
  115. if (io_port == 0 || io_port == 3)
  116. gpiommgpio->control[control_port] &= ~BIT(4);
  117. else
  118. gpiommgpio->control[control_port] &= ~BIT(1);
  119. }
  120. if (value)
  121. gpiommgpio->out_state[io_port] |= mask;
  122. else
  123. gpiommgpio->out_state[io_port] &= ~mask;
  124. control = BIT(7) | gpiommgpio->control[control_port];
  125. outb(control, control_addr);
  126. outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
  127. spin_unlock_irqrestore(&gpiommgpio->lock, flags);
  128. return 0;
  129. }
  130. static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
  131. {
  132. struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
  133. const unsigned int port = offset / 8;
  134. const unsigned int mask = BIT(offset % 8);
  135. const unsigned int in_port = (port > 2) ? port + 1 : port;
  136. unsigned long flags;
  137. unsigned int port_state;
  138. spin_lock_irqsave(&gpiommgpio->lock, flags);
  139. /* ensure that GPIO is set for input */
  140. if (!(gpiommgpio->io_state[port] & mask)) {
  141. spin_unlock_irqrestore(&gpiommgpio->lock, flags);
  142. return -EINVAL;
  143. }
  144. port_state = inb(gpiommgpio->base + in_port);
  145. spin_unlock_irqrestore(&gpiommgpio->lock, flags);
  146. return !!(port_state & mask);
  147. }
  148. static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
  149. int value)
  150. {
  151. struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
  152. const unsigned int port = offset / 8;
  153. const unsigned int mask = BIT(offset % 8);
  154. const unsigned int out_port = (port > 2) ? port + 1 : port;
  155. unsigned long flags;
  156. spin_lock_irqsave(&gpiommgpio->lock, flags);
  157. if (value)
  158. gpiommgpio->out_state[port] |= mask;
  159. else
  160. gpiommgpio->out_state[port] &= ~mask;
  161. outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
  162. spin_unlock_irqrestore(&gpiommgpio->lock, flags);
  163. }
  164. static int gpiomm_probe(struct device *dev, unsigned int id)
  165. {
  166. struct gpiomm_gpio *gpiommgpio;
  167. const char *const name = dev_name(dev);
  168. int err;
  169. gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
  170. if (!gpiommgpio)
  171. return -ENOMEM;
  172. if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
  173. dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
  174. base[id], base[id] + GPIOMM_EXTENT);
  175. return -EBUSY;
  176. }
  177. gpiommgpio->chip.label = name;
  178. gpiommgpio->chip.parent = dev;
  179. gpiommgpio->chip.owner = THIS_MODULE;
  180. gpiommgpio->chip.base = -1;
  181. gpiommgpio->chip.ngpio = 48;
  182. gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
  183. gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
  184. gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
  185. gpiommgpio->chip.get = gpiomm_gpio_get;
  186. gpiommgpio->chip.set = gpiomm_gpio_set;
  187. gpiommgpio->base = base[id];
  188. spin_lock_init(&gpiommgpio->lock);
  189. dev_set_drvdata(dev, gpiommgpio);
  190. err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
  191. if (err) {
  192. dev_err(dev, "GPIO registering failed (%d)\n", err);
  193. return err;
  194. }
  195. /* initialize all GPIO as output */
  196. outb(0x80, base[id] + 3);
  197. outb(0x00, base[id]);
  198. outb(0x00, base[id] + 1);
  199. outb(0x00, base[id] + 2);
  200. outb(0x80, base[id] + 7);
  201. outb(0x00, base[id] + 4);
  202. outb(0x00, base[id] + 5);
  203. outb(0x00, base[id] + 6);
  204. return 0;
  205. }
  206. static int gpiomm_remove(struct device *dev, unsigned int id)
  207. {
  208. struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
  209. gpiochip_remove(&gpiommgpio->chip);
  210. return 0;
  211. }
  212. static struct isa_driver gpiomm_driver = {
  213. .probe = gpiomm_probe,
  214. .driver = {
  215. .name = "gpio-mm"
  216. },
  217. .remove = gpiomm_remove
  218. };
  219. module_isa_driver(gpiomm_driver, num_gpiomm);
  220. MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
  221. MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
  222. MODULE_LICENSE("GPL v2");