gpio-siox.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
  4. */
  5. #include <linux/module.h>
  6. #include <linux/siox.h>
  7. #include <linux/gpio/driver.h>
  8. #include <linux/of.h>
  9. struct gpio_siox_ddata {
  10. struct gpio_chip gchip;
  11. struct irq_chip ichip;
  12. struct mutex lock;
  13. u8 setdata[1];
  14. u8 getdata[3];
  15. spinlock_t irqlock;
  16. u32 irq_enable;
  17. u32 irq_status;
  18. u32 irq_type[20];
  19. };
  20. /*
  21. * Note that this callback only sets the value that is clocked out in the next
  22. * cycle.
  23. */
  24. static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
  25. {
  26. struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
  27. mutex_lock(&ddata->lock);
  28. buf[0] = ddata->setdata[0];
  29. mutex_unlock(&ddata->lock);
  30. return 0;
  31. }
  32. static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
  33. {
  34. struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
  35. size_t offset;
  36. u32 trigger;
  37. mutex_lock(&ddata->lock);
  38. spin_lock_irq(&ddata->irqlock);
  39. for (offset = 0; offset < 12; ++offset) {
  40. unsigned int bitpos = 11 - offset;
  41. unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
  42. unsigned int prev_level =
  43. ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
  44. u32 irq_type = ddata->irq_type[offset];
  45. if (gpiolevel) {
  46. if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
  47. ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
  48. ddata->irq_status |= 1 << offset;
  49. } else {
  50. if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
  51. ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
  52. ddata->irq_status |= 1 << offset;
  53. }
  54. }
  55. trigger = ddata->irq_status & ddata->irq_enable;
  56. spin_unlock_irq(&ddata->irqlock);
  57. ddata->getdata[0] = buf[0];
  58. ddata->getdata[1] = buf[1];
  59. ddata->getdata[2] = buf[2];
  60. mutex_unlock(&ddata->lock);
  61. for (offset = 0; offset < 12; ++offset) {
  62. if (trigger & (1 << offset)) {
  63. struct irq_domain *irqdomain = ddata->gchip.irq.domain;
  64. unsigned int irq = irq_find_mapping(irqdomain, offset);
  65. /*
  66. * Conceptually handle_nested_irq should call the flow
  67. * handler of the irq chip. But it doesn't, so we have
  68. * to clean the irq_status here.
  69. */
  70. spin_lock_irq(&ddata->irqlock);
  71. ddata->irq_status &= ~(1 << offset);
  72. spin_unlock_irq(&ddata->irqlock);
  73. handle_nested_irq(irq);
  74. }
  75. }
  76. return 0;
  77. }
  78. static void gpio_siox_irq_ack(struct irq_data *d)
  79. {
  80. struct irq_chip *ic = irq_data_get_irq_chip(d);
  81. struct gpio_siox_ddata *ddata =
  82. container_of(ic, struct gpio_siox_ddata, ichip);
  83. spin_lock_irq(&ddata->irqlock);
  84. ddata->irq_status &= ~(1 << d->hwirq);
  85. spin_unlock_irq(&ddata->irqlock);
  86. }
  87. static void gpio_siox_irq_mask(struct irq_data *d)
  88. {
  89. struct irq_chip *ic = irq_data_get_irq_chip(d);
  90. struct gpio_siox_ddata *ddata =
  91. container_of(ic, struct gpio_siox_ddata, ichip);
  92. spin_lock_irq(&ddata->irqlock);
  93. ddata->irq_enable &= ~(1 << d->hwirq);
  94. spin_unlock_irq(&ddata->irqlock);
  95. }
  96. static void gpio_siox_irq_unmask(struct irq_data *d)
  97. {
  98. struct irq_chip *ic = irq_data_get_irq_chip(d);
  99. struct gpio_siox_ddata *ddata =
  100. container_of(ic, struct gpio_siox_ddata, ichip);
  101. spin_lock_irq(&ddata->irqlock);
  102. ddata->irq_enable |= 1 << d->hwirq;
  103. spin_unlock_irq(&ddata->irqlock);
  104. }
  105. static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
  106. {
  107. struct irq_chip *ic = irq_data_get_irq_chip(d);
  108. struct gpio_siox_ddata *ddata =
  109. container_of(ic, struct gpio_siox_ddata, ichip);
  110. spin_lock_irq(&ddata->irqlock);
  111. ddata->irq_type[d->hwirq] = type;
  112. spin_unlock_irq(&ddata->irqlock);
  113. return 0;
  114. }
  115. static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
  116. {
  117. struct gpio_siox_ddata *ddata =
  118. container_of(chip, struct gpio_siox_ddata, gchip);
  119. int ret;
  120. mutex_lock(&ddata->lock);
  121. if (offset >= 12) {
  122. unsigned int bitpos = 19 - offset;
  123. ret = ddata->setdata[0] & (1 << bitpos);
  124. } else {
  125. unsigned int bitpos = 11 - offset;
  126. ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
  127. }
  128. mutex_unlock(&ddata->lock);
  129. return ret;
  130. }
  131. static void gpio_siox_set(struct gpio_chip *chip,
  132. unsigned int offset, int value)
  133. {
  134. struct gpio_siox_ddata *ddata =
  135. container_of(chip, struct gpio_siox_ddata, gchip);
  136. u8 mask = 1 << (19 - offset);
  137. mutex_lock(&ddata->lock);
  138. if (value)
  139. ddata->setdata[0] |= mask;
  140. else
  141. ddata->setdata[0] &= ~mask;
  142. mutex_unlock(&ddata->lock);
  143. }
  144. static int gpio_siox_direction_input(struct gpio_chip *chip,
  145. unsigned int offset)
  146. {
  147. if (offset >= 12)
  148. return -EINVAL;
  149. return 0;
  150. }
  151. static int gpio_siox_direction_output(struct gpio_chip *chip,
  152. unsigned int offset, int value)
  153. {
  154. if (offset < 12)
  155. return -EINVAL;
  156. gpio_siox_set(chip, offset, value);
  157. return 0;
  158. }
  159. static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
  160. {
  161. if (offset < 12)
  162. return 1; /* input */
  163. else
  164. return 0; /* output */
  165. }
  166. static int gpio_siox_probe(struct siox_device *sdevice)
  167. {
  168. struct gpio_siox_ddata *ddata;
  169. int ret;
  170. ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
  171. if (!ddata)
  172. return -ENOMEM;
  173. dev_set_drvdata(&sdevice->dev, ddata);
  174. mutex_init(&ddata->lock);
  175. spin_lock_init(&ddata->irqlock);
  176. ddata->gchip.base = -1;
  177. ddata->gchip.can_sleep = 1;
  178. ddata->gchip.parent = &sdevice->dev;
  179. ddata->gchip.owner = THIS_MODULE;
  180. ddata->gchip.get = gpio_siox_get;
  181. ddata->gchip.set = gpio_siox_set;
  182. ddata->gchip.direction_input = gpio_siox_direction_input;
  183. ddata->gchip.direction_output = gpio_siox_direction_output;
  184. ddata->gchip.get_direction = gpio_siox_get_direction;
  185. ddata->gchip.ngpio = 20;
  186. ddata->ichip.name = "siox-gpio";
  187. ddata->ichip.irq_ack = gpio_siox_irq_ack;
  188. ddata->ichip.irq_mask = gpio_siox_irq_mask;
  189. ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
  190. ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
  191. ret = gpiochip_add(&ddata->gchip);
  192. if (ret) {
  193. dev_err(&sdevice->dev,
  194. "Failed to register gpio chip (%d)\n", ret);
  195. goto err_gpiochip;
  196. }
  197. ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
  198. 0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
  199. if (ret) {
  200. dev_err(&sdevice->dev,
  201. "Failed to register irq chip (%d)\n", ret);
  202. err_gpiochip:
  203. gpiochip_remove(&ddata->gchip);
  204. }
  205. return ret;
  206. }
  207. static int gpio_siox_remove(struct siox_device *sdevice)
  208. {
  209. struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
  210. gpiochip_remove(&ddata->gchip);
  211. return 0;
  212. }
  213. static struct siox_driver gpio_siox_driver = {
  214. .probe = gpio_siox_probe,
  215. .remove = gpio_siox_remove,
  216. .set_data = gpio_siox_set_data,
  217. .get_data = gpio_siox_get_data,
  218. .driver = {
  219. .name = "gpio-siox",
  220. },
  221. };
  222. static int __init gpio_siox_init(void)
  223. {
  224. return siox_driver_register(&gpio_siox_driver);
  225. }
  226. module_init(gpio_siox_init);
  227. static void __exit gpio_siox_exit(void)
  228. {
  229. siox_driver_unregister(&gpio_siox_driver);
  230. }
  231. module_exit(gpio_siox_exit);
  232. MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
  233. MODULE_DESCRIPTION("SIOX gpio driver");
  234. MODULE_LICENSE("GPL v2");