linux-007-gpio-helper.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. diff -Naurp a/drivers/gpio/gpio-of-helper.c b/drivers/gpio/gpio-of-helper.c
  2. --- a/drivers/gpio/gpio-of-helper.c 1970-01-01 01:00:00.000000000 +0100
  3. +++ b/drivers/gpio/gpio-of-helper.c 2015-10-30 21:13:09.834705182 +0100
  4. @@ -0,0 +1,414 @@
  5. +/*
  6. + * GPIO OF based helper
  7. + *
  8. + * A simple DT based driver to provide access to GPIO functionality
  9. + * to user-space via sysfs.
  10. + *
  11. + * Copyright (C) 2013 Pantelis Antoniou <panto@antoniou-consulting.com>
  12. + *
  13. + * This program is free software; you can redistribute it and/or modify
  14. + * it under the terms of the GNU General Public License as published by
  15. + * the Free Software Foundation; either version 2 of the License, or
  16. + * (at your option) any later version.
  17. + *
  18. + * This program is distributed in the hope that it will be useful,
  19. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. + * GNU General Public License for more details.
  22. + *
  23. + * You should have received a copy of the GNU General Public License
  24. + * along with this program; if not, write to the Free Software
  25. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. + */
  27. +
  28. +#include <linux/module.h>
  29. +#include <linux/kernel.h>
  30. +#include <linux/string.h>
  31. +#include <linux/timer.h>
  32. +#include <linux/errno.h>
  33. +#include <linux/init.h>
  34. +#include <linux/delay.h>
  35. +#include <linux/bitops.h>
  36. +#include <linux/err.h>
  37. +#include <linux/of.h>
  38. +#include <linux/of_device.h>
  39. +#include <linux/of_gpio.h>
  40. +#include <linux/pinctrl/pinctrl.h>
  41. +#include <linux/pinctrl/pinmux.h>
  42. +#include <linux/pinctrl/consumer.h>
  43. +#include <linux/atomic.h>
  44. +#include <linux/clk.h>
  45. +#include <linux/interrupt.h>
  46. +#include <linux/math64.h>
  47. +#include <linux/atomic.h>
  48. +#include <linux/idr.h>
  49. +
  50. +/* fwd decl. */
  51. +struct gpio_of_helper_info;
  52. +
  53. +enum gpio_type {
  54. + GPIO_TYPE_INPUT = 0,
  55. + GPIO_TYPE_OUTPUT = 1,
  56. +};
  57. +
  58. +struct gpio_of_entry {
  59. + int id;
  60. + struct gpio_of_helper_info *info;
  61. + struct device_node *node;
  62. + enum gpio_type type;
  63. + int gpio;
  64. + enum of_gpio_flags gpio_flags;
  65. + int irq;
  66. + const char *name;
  67. + atomic64_t counter;
  68. + unsigned int count_flags;
  69. +#define COUNT_RISING_EDGE (1 << 0)
  70. +#define COUNT_FALLING_EDGE (1 << 1)
  71. +};
  72. +
  73. +struct gpio_of_helper_info {
  74. + struct platform_device *pdev;
  75. + struct idr idr;
  76. +};
  77. +
  78. +static const struct of_device_id gpio_of_helper_of_match[] = {
  79. + {
  80. + .compatible = "gpio-of-helper",
  81. + },
  82. + { },
  83. +};
  84. +MODULE_DEVICE_TABLE(of, gpio_of_helper_of_match);
  85. +
  86. +static ssize_t gpio_of_helper_show_status(struct device *dev,
  87. + struct device_attribute *attr, char *buf)
  88. +{
  89. + struct platform_device *pdev = to_platform_device(dev);
  90. + struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
  91. + struct gpio_of_entry *entry;
  92. + char *p, *e;
  93. + int id, n;
  94. +
  95. + p = buf;
  96. + e = p + PAGE_SIZE;
  97. + n = 0;
  98. + idr_for_each_entry(&info->idr, entry, id) {
  99. + switch (entry->type) {
  100. + case GPIO_TYPE_INPUT:
  101. + n = snprintf(p, e - p, "%2d %-24s %3d %-3s %llu\n",
  102. + entry->id, entry->name, entry->gpio, "IN",
  103. + (unsigned long long)
  104. + atomic64_read(&entry->counter));
  105. + break;
  106. + case GPIO_TYPE_OUTPUT:
  107. + n = snprintf(p, e - p, "%2d %-24s %3d %-3s\n",
  108. + entry->id, entry->name, entry->gpio, "OUT");
  109. + break;
  110. + }
  111. + p += n;
  112. + }
  113. +
  114. + return p - buf;
  115. +}
  116. +
  117. +static DEVICE_ATTR(status, S_IRUGO,
  118. + gpio_of_helper_show_status, NULL);
  119. +
  120. +static irqreturn_t gpio_of_helper_handler(int irq, void *ptr)
  121. +{
  122. + struct gpio_of_entry *entry = ptr;
  123. +
  124. + /* caution - low speed interfaces only! */
  125. + atomic64_inc(&entry->counter);
  126. +
  127. + return IRQ_HANDLED;
  128. +}
  129. +
  130. +static struct gpio_of_entry *
  131. +gpio_of_entry_create(struct gpio_of_helper_info *info,
  132. + struct device_node *node)
  133. +{
  134. + struct platform_device *pdev = info->pdev;
  135. + struct device *dev = &pdev->dev;
  136. + struct gpio_of_entry *entry;
  137. + int err, gpio, irq;
  138. + unsigned int req_flags, count_flags, irq_flags;
  139. + enum gpio_type type;
  140. + enum of_gpio_flags gpio_flags;
  141. + const char *name;
  142. +
  143. + /* get the type of the node first */
  144. + if (of_property_read_bool(node, "input"))
  145. + type = GPIO_TYPE_INPUT;
  146. + else if (of_property_read_bool(node, "output"))
  147. + type = GPIO_TYPE_OUTPUT;
  148. + else {
  149. + dev_err(dev, "Not valid gpio node type\n");
  150. + err = -EINVAL;
  151. + goto err_bad_node;
  152. + }
  153. +
  154. + /* get the name */
  155. + err = of_property_read_string(node, "gpio-name", &name);
  156. + if (err != 0) {
  157. + dev_err(dev, "Failed to get name property\n");
  158. + goto err_bad_node;
  159. + }
  160. +
  161. + err = of_get_named_gpio_flags(node, "gpio", 0, &gpio_flags);
  162. + if (IS_ERR_VALUE(err)) {
  163. + dev_err(dev, "Failed to get gpio property of '%s'\n", name);
  164. + goto err_bad_node;
  165. + }
  166. + gpio = err;
  167. +
  168. + req_flags = 0;
  169. + count_flags = 0;
  170. +
  171. + /* set the request flags */
  172. + switch (type) {
  173. + case GPIO_TYPE_INPUT:
  174. + req_flags = GPIOF_DIR_IN | GPIOF_EXPORT;
  175. + if (of_property_read_bool(node, "count-falling-edge"))
  176. + count_flags |= COUNT_FALLING_EDGE;
  177. + if (of_property_read_bool(node, "count-rising-edge"))
  178. + count_flags |= COUNT_RISING_EDGE;
  179. + break;
  180. + case GPIO_TYPE_OUTPUT:
  181. + req_flags = GPIOF_DIR_OUT | GPIOF_EXPORT;
  182. + if (of_property_read_bool(node, "init-high"))
  183. + req_flags |= GPIOF_OUT_INIT_HIGH;
  184. + else if (of_property_read_bool(node, "init-low"))
  185. + req_flags |= GPIOF_OUT_INIT_LOW;
  186. + break;
  187. + }
  188. +
  189. + /* request the gpio */
  190. + err = devm_gpio_request_one(dev, gpio, req_flags, name);
  191. + if (err != 0) {
  192. + dev_err(dev, "Failed to request gpio '%s'\n", name);
  193. + goto err_bad_node;
  194. + }
  195. +
  196. + irq = -1;
  197. + irq_flags = 0;
  198. +
  199. + /* counter mode requested - need an interrupt */
  200. + if (count_flags != 0) {
  201. + irq = gpio_to_irq(gpio);
  202. + if (IS_ERR_VALUE(irq)) {
  203. + dev_err(dev, "Failed to request gpio '%s'\n", name);
  204. + goto err_bad_node;
  205. + }
  206. +
  207. + if (count_flags & COUNT_RISING_EDGE)
  208. + irq_flags |= IRQF_TRIGGER_RISING;
  209. + if (count_flags & COUNT_FALLING_EDGE)
  210. + irq_flags |= IRQF_TRIGGER_FALLING;
  211. + }
  212. +
  213. + if (!idr_pre_get(&info->idr, GFP_KERNEL)) {
  214. + dev_err(dev, "Failed on idr_pre_get of '%s'\n", name);
  215. + err = -ENOMEM;
  216. + goto err_no_mem;
  217. + }
  218. +
  219. + entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
  220. + if (entry == NULL) {
  221. + dev_err(dev, "Failed to allocate gpio entry of '%s'\n", name);
  222. + err = -ENOMEM;
  223. + goto err_no_mem;
  224. + }
  225. +
  226. + entry->id = -1;
  227. + entry->info = info;
  228. + entry->node = of_node_get(node); /* get node reference */
  229. + entry->type = type;
  230. + entry->gpio = gpio;
  231. + entry->gpio_flags = gpio_flags;
  232. + entry->irq = irq;
  233. + entry->name = name;
  234. +
  235. + /* interrupt enable is last thing done */
  236. + if (irq >= 0) {
  237. + atomic64_set(&entry->counter, 0);
  238. + entry->count_flags = count_flags;
  239. + err = devm_request_irq(dev, irq, gpio_of_helper_handler,
  240. + irq_flags, name, entry);
  241. + if (err != 0) {
  242. + dev_err(dev, "Failed to request irq of '%s'\n", name);
  243. + goto err_no_irq;
  244. + }
  245. + }
  246. +
  247. + /* all done; insert */
  248. + err = idr_get_new(&info->idr, entry, &entry->id);
  249. + if (IS_ERR_VALUE(err)) {
  250. + dev_err(dev, "Failed to idr_get_new of '%s'\n", name);
  251. + goto err_fail_idr;
  252. + }
  253. +
  254. + dev_info(dev, "Allocated GPIO id=%d\n", entry->id);
  255. +
  256. + return entry;
  257. +
  258. +err_fail_idr:
  259. + /* nothing to do */
  260. +err_no_irq:
  261. + /* release node ref */
  262. + of_node_put(node);
  263. + /* nothing else needs to be done, devres handles it */
  264. +err_no_mem:
  265. +err_bad_node:
  266. + return ERR_PTR(err);
  267. +}
  268. +
  269. +static int gpio_of_entry_destroy(struct gpio_of_entry *entry)
  270. +{
  271. + struct gpio_of_helper_info *info = entry->info;
  272. + struct platform_device *pdev = info->pdev;
  273. + struct device *dev = &pdev->dev;
  274. +
  275. + dev_info(dev, "Destroying GPIO id=%d\n", entry->id);
  276. +
  277. + /* remove from the IDR */
  278. + idr_remove(&info->idr, entry->id);
  279. +
  280. + /* remove node ref */
  281. + of_node_put(entry->node);
  282. +
  283. + /* free gpio */
  284. + devm_gpio_free(dev, entry->gpio);
  285. +
  286. + /* gree irq */
  287. + if (entry->irq >= 0)
  288. + devm_free_irq(dev, entry->irq, entry);
  289. +
  290. + /* and free */
  291. + devm_kfree(dev, entry);
  292. +
  293. + return 0;
  294. +}
  295. +
  296. +static int gpio_of_helper_probe(struct platform_device *pdev)
  297. +{
  298. + struct device *dev = &pdev->dev;
  299. + struct gpio_of_helper_info *info;
  300. + struct gpio_of_entry *entry;
  301. + struct device_node *pnode = pdev->dev.of_node;
  302. + struct device_node *cnode;
  303. + struct pinctrl *pinctrl;
  304. + int err;
  305. +
  306. + /* we only support OF */
  307. + if (pnode == NULL) {
  308. + dev_err(&pdev->dev, "No platform of_node!\n");
  309. + return -ENODEV;
  310. + }
  311. +
  312. + pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
  313. + if (IS_ERR(pinctrl)) {
  314. + /* special handling for probe defer */
  315. + if (PTR_ERR(pinctrl) == -EPROBE_DEFER)
  316. + return -EPROBE_DEFER;
  317. +
  318. + dev_warn(&pdev->dev,
  319. + "pins are not configured from the driver\n");
  320. + }
  321. +
  322. + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
  323. + if (info == NULL) {
  324. + dev_err(&pdev->dev, "Failed to allocate info\n");
  325. + err = -ENOMEM;
  326. + goto err_no_mem;
  327. + }
  328. + platform_set_drvdata(pdev, info);
  329. + info->pdev = pdev;
  330. +
  331. + idr_init(&info->idr);
  332. +
  333. + err = device_create_file(dev, &dev_attr_status);
  334. + if (err != 0) {
  335. + dev_err(dev, "Failed to create status sysfs attribute\n");
  336. + goto err_no_sysfs;
  337. + }
  338. +
  339. + for_each_child_of_node(pnode, cnode) {
  340. +
  341. + entry = gpio_of_entry_create(info, cnode);
  342. + if (IS_ERR_OR_NULL(entry)) {
  343. + dev_err(dev, "Failed to create gpio entry\n");
  344. + err = PTR_ERR(entry);
  345. + goto err_fail_entry;
  346. + }
  347. + }
  348. +
  349. + dev_info(&pdev->dev, "ready\n");
  350. +
  351. + return 0;
  352. +err_fail_entry:
  353. + device_remove_file(&pdev->dev, &dev_attr_status);
  354. +err_no_sysfs:
  355. +err_no_mem:
  356. + return err;
  357. +}
  358. +
  359. +static int gpio_of_helper_remove(struct platform_device *pdev)
  360. +{
  361. + struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
  362. + struct gpio_of_entry *entry;
  363. + int id;
  364. +
  365. + dev_info(&pdev->dev, "removing\n");
  366. +
  367. + device_remove_file(&pdev->dev, &dev_attr_status);
  368. +
  369. + id = 0;
  370. + idr_for_each_entry(&info->idr, entry, id) {
  371. + /* destroy each and every one */
  372. + gpio_of_entry_destroy(entry);
  373. + }
  374. +
  375. + return 0;
  376. +}
  377. +
  378. +#ifdef CONFIG_PM
  379. +#ifdef CONFIG_PM_RUNTIME
  380. +static int gpio_of_helper_runtime_suspend(struct device *dev)
  381. +{
  382. + /* place holder */
  383. + return 0;
  384. +}
  385. +
  386. +static int gpio_of_helper_runtime_resume(struct device *dev)
  387. +{
  388. + /* place holder */
  389. + return 0;
  390. +}
  391. +#endif /* CONFIG_PM_RUNTIME */
  392. +
  393. +static struct dev_pm_ops gpio_of_helper_pm_ops = {
  394. + SET_RUNTIME_PM_OPS(gpio_of_helper_runtime_suspend,
  395. + gpio_of_helper_runtime_resume, NULL)
  396. +};
  397. +#define GPIO_OF_HELPER_PM_OPS (&gpio_of_helper_pm_ops)
  398. +#else
  399. +#define GPIO_OF_HELPER_PM_OPS NULL
  400. +#endif /* CONFIG_PM */
  401. +
  402. +struct platform_driver gpio_of_helper_driver = {
  403. + .probe = gpio_of_helper_probe,
  404. + .remove = gpio_of_helper_remove,
  405. + .driver = {
  406. + .name = "gpio-of-helper",
  407. + .owner = THIS_MODULE,
  408. + .pm = GPIO_OF_HELPER_PM_OPS,
  409. + .of_match_table = gpio_of_helper_of_match,
  410. + },
  411. +};
  412. +
  413. +module_platform_driver(gpio_of_helper_driver);
  414. +
  415. +MODULE_AUTHOR("Pantelis Antoniou <panto@antoniou-consulting.com>");
  416. +MODULE_DESCRIPTION("GPIO OF Helper driver");
  417. +MODULE_LICENSE("GPL");
  418. +MODULE_ALIAS("platform:gpio-of-helper");
  419. diff -Naurp a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
  420. --- a/drivers/gpio/Kconfig 2014-02-07 00:05:20.000000000 +0100
  421. +++ b/drivers/gpio/Kconfig 2015-10-30 21:13:09.826705188 +0100
  422. @@ -81,6 +81,20 @@ config GPIO_SYSFS
  423. Kernel drivers may also request that a particular GPIO be
  424. exported to userspace; this can be useful when debugging.
  425. +config GPIO_OF_HELPER
  426. + bool "GPIO OF helper device"
  427. + depends on OF_GPIO
  428. + help
  429. + Say Y here to add an GPIO OF helper driver
  430. +
  431. + Allows you specify a GPIO helper based on OF
  432. + which allows simple export of GPIO functionality
  433. + in user-space.
  434. +
  435. + Features include, value set/get, direction control,
  436. + interrupt/value change poll support, event counting
  437. + and others.
  438. +
  439. config GPIO_GENERIC
  440. tristate
  441. diff -Naurp a/drivers/gpio/Makefile b/drivers/gpio/Makefile
  442. --- a/drivers/gpio/Makefile 2014-02-07 00:05:20.000000000 +0100
  443. +++ b/drivers/gpio/Makefile 2015-10-30 21:13:09.826705188 +0100
  444. @@ -6,6 +6,7 @@ obj-$(CONFIG_GPIO_DEVRES) += devres.o
  445. obj-$(CONFIG_GPIOLIB) += gpiolib.o
  446. obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
  447. obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
  448. +obj-$(CONFIG_GPIO_OF_HELPER) += gpio-of-helper.o
  449. # Device drivers. Generally keep list sorted alphabetically
  450. obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o