2
0

801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. From fc23ea48ba52c24f201fe5ca0132ee1a3de5a70a Mon Sep 17 00:00:00 2001
  2. From: Mauri Sandberg <[email protected]>
  3. Date: Thu, 25 Mar 2021 11:48:05 +0200
  4. Subject: [PATCH 2/2] gpio: gpio-cascade: add generic GPIO cascade
  5. Adds support for building cascades of GPIO lines. That is, it allows
  6. setups when there is one upstream line and multiple cascaded lines, out
  7. of which one can be chosen at a time. The status of the upstream line
  8. can be conveyed to the selected cascaded line or, vice versa, the status
  9. of the cascaded line can be conveyed to the upstream line.
  10. A multiplexer is being used to select, which cascaded GPIO line is being
  11. used at any given time.
  12. At the moment only input direction is supported. In future it should be
  13. possible to add support for output direction, too.
  14. Signed-off-by: Mauri Sandberg <[email protected]>
  15. Reviewed-by: Linus Walleij <[email protected]>
  16. Reviewed-by: Andy Shevchenko <[email protected]>
  17. ---
  18. v7 -> v8:
  19. - rearrange members in struct gpio_cascade
  20. - cosmetic changes in file header and in one function declaration
  21. - added Reviewed-by tags by Linus and Andy
  22. v6 -> v7:
  23. - In Kconfig add info about module name
  24. - adhere to new convention that allows lines longer than 80 chars
  25. - use dev_probe_err with upstream gpio line too
  26. - refactor for cleaner exit of probe function.
  27. v5 -> v6:
  28. - In Kconfig, remove dependency to OF_GPIO and select only MULTIPLEXER
  29. - refactor code preferring one-liners
  30. - clean up prints, removing them from success-path.
  31. - don't explicitly set gpio_chip.of_node as it's done in the GPIO library
  32. - use devm_gpiochip_add_data instead of gpiochip_add
  33. v4 -> v5:
  34. - renamed gpio-mux-input -> gpio-cascade. refactored code accordingly
  35. here and there and changed to use new bindings and compatible string
  36. - ambigious and vague 'pin' was rename to 'upstream_line'
  37. - dropped Tested-by and Reviewed-by due to changes in bindings
  38. - dropped Reported-by suggested by an automatic bot as it was not really
  39. appropriate to begin with
  40. - functionally it's the same as v4
  41. v3 -> v4:
  42. - Changed author email
  43. - Included Tested-by and Reviewed-by from Drew
  44. v2 -> v3:
  45. - use managed device resources
  46. - update Kconfig description
  47. v1 -> v2:
  48. - removed .owner from platform_driver as per test bot's instruction
  49. - added MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE
  50. - added gpio_mux_input_get_direction as it's recommended for all chips
  51. - removed because this is input only chip: gpio_mux_input_set_value
  52. - removed because they are not needed for input/output only chips:
  53. gpio_mux_input_direction_input
  54. gpio_mux_input_direction_output
  55. - fixed typo in an error message
  56. - added info message about successful registration
  57. - removed can_sleep flag as this does not sleep while getting GPIO value
  58. like I2C or SPI do
  59. - Updated description in Kconfig
  60. ---
  61. drivers/gpio/Kconfig | 15 +++++
  62. drivers/gpio/Makefile | 1 +
  63. drivers/gpio/gpio-cascade.c | 117 ++++++++++++++++++++++++++++++++++++
  64. 3 files changed, 133 insertions(+)
  65. create mode 100644 drivers/gpio/gpio-cascade.c
  66. --- a/drivers/gpio/Kconfig
  67. +++ b/drivers/gpio/Kconfig
  68. @@ -1820,4 +1820,19 @@ config GPIO_SIM
  69. endmenu
  70. +comment "Other GPIO expanders"
  71. +
  72. +config GPIO_CASCADE
  73. + tristate "General GPIO cascade"
  74. + select MULTIPLEXER
  75. + help
  76. + Say yes here to enable support for generic GPIO cascade.
  77. +
  78. + This allows building one-to-many cascades of GPIO lines using
  79. + different types of multiplexers readily available. At the
  80. + moment only input lines are supported.
  81. +
  82. + To build the driver as a module choose 'm' and the resulting module
  83. + will be called 'gpio-cascade'.
  84. +
  85. endif
  86. --- a/drivers/gpio/Makefile
  87. +++ b/drivers/gpio/Makefile
  88. @@ -44,6 +44,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd
  89. obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
  90. obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
  91. obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
  92. +obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o
  93. obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
  94. obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
  95. obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
  96. --- /dev/null
  97. +++ b/drivers/gpio/gpio-cascade.c
  98. @@ -0,0 +1,117 @@
  99. +// SPDX-License-Identifier: GPL-2.0-only
  100. +/*
  101. + * A generic GPIO cascade driver
  102. + *
  103. + * Copyright (C) 2021 Mauri Sandberg <[email protected]>
  104. + *
  105. + * This allows building cascades of GPIO lines in a manner illustrated
  106. + * below:
  107. + *
  108. + * /|---- Cascaded GPIO line 0
  109. + * Upstream | |---- Cascaded GPIO line 1
  110. + * GPIO line ----+ | .
  111. + * | | .
  112. + * \|---- Cascaded GPIO line n
  113. + *
  114. + * A multiplexer is being used to select, which cascaded line is being
  115. + * addressed at any given time.
  116. + *
  117. + * At the moment only input mode is supported due to lack of means for
  118. + * testing output functionality. At least theoretically output should be
  119. + * possible with open drain constructions.
  120. + */
  121. +
  122. +#include <linux/module.h>
  123. +#include <linux/slab.h>
  124. +#include <linux/platform_device.h>
  125. +#include <linux/mux/consumer.h>
  126. +
  127. +#include <linux/gpio/consumer.h>
  128. +#include <linux/gpio/driver.h>
  129. +
  130. +struct gpio_cascade {
  131. + struct gpio_chip gpio_chip;
  132. + struct device *parent;
  133. + struct mux_control *mux_control;
  134. + struct gpio_desc *upstream_line;
  135. +};
  136. +
  137. +static struct gpio_cascade *chip_to_cascade(struct gpio_chip *gc)
  138. +{
  139. + return container_of(gc, struct gpio_cascade, gpio_chip);
  140. +}
  141. +
  142. +static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset)
  143. +{
  144. + return GPIO_LINE_DIRECTION_IN;
  145. +}
  146. +
  147. +static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset)
  148. +{
  149. + struct gpio_cascade *cas = chip_to_cascade(gc);
  150. + int ret;
  151. +
  152. + ret = mux_control_select(cas->mux_control, offset);
  153. + if (ret)
  154. + return ret;
  155. +
  156. + ret = gpiod_get_value(cas->upstream_line);
  157. + mux_control_deselect(cas->mux_control);
  158. + return ret;
  159. +}
  160. +
  161. +static int gpio_cascade_probe(struct platform_device *pdev)
  162. +{
  163. + struct device *dev = &pdev->dev;
  164. + struct gpio_cascade *cas;
  165. + struct mux_control *mc;
  166. + struct gpio_desc *upstream;
  167. + struct gpio_chip *gc;
  168. +
  169. + cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL);
  170. + if (!cas)
  171. + return -ENOMEM;
  172. +
  173. + mc = devm_mux_control_get(dev, NULL);
  174. + if (IS_ERR(mc))
  175. + return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n");
  176. +
  177. + cas->mux_control = mc;
  178. + upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN);
  179. + if (IS_ERR(upstream))
  180. + return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n");
  181. +
  182. + cas->upstream_line = upstream;
  183. + cas->parent = dev;
  184. +
  185. + gc = &cas->gpio_chip;
  186. + gc->get = gpio_cascade_get_value;
  187. + gc->get_direction = gpio_cascade_get_direction;
  188. + gc->base = -1;
  189. + gc->ngpio = mux_control_states(mc);
  190. + gc->label = dev_name(cas->parent);
  191. + gc->parent = cas->parent;
  192. + gc->owner = THIS_MODULE;
  193. +
  194. + platform_set_drvdata(pdev, cas);
  195. + return devm_gpiochip_add_data(dev, &cas->gpio_chip, NULL);
  196. +}
  197. +
  198. +static const struct of_device_id gpio_cascade_id[] = {
  199. + { .compatible = "gpio-cascade" },
  200. + { /* sentinel */ }
  201. +};
  202. +MODULE_DEVICE_TABLE(of, gpio_cascade_id);
  203. +
  204. +static struct platform_driver gpio_cascade_driver = {
  205. + .driver = {
  206. + .name = "gpio-cascade",
  207. + .of_match_table = gpio_cascade_id,
  208. + },
  209. + .probe = gpio_cascade_probe,
  210. +};
  211. +module_platform_driver(gpio_cascade_driver);
  212. +
  213. +MODULE_AUTHOR("Mauri Sandberg <[email protected]>");
  214. +MODULE_DESCRIPTION("Generic GPIO cascade");
  215. +MODULE_LICENSE("GPL");