gpio-brcmstb.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (C) 2015 Broadcom Corporation
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation version 2.
  7. *
  8. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  9. * kind, whether express or implied; without even the implied warranty
  10. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <linux/bitops.h>
  14. #include <linux/gpio/driver.h>
  15. #include <linux/of_device.h>
  16. #include <linux/of_irq.h>
  17. #include <linux/module.h>
  18. #include <linux/basic_mmio_gpio.h>
  19. #define GIO_BANK_SIZE 0x20
  20. #define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
  21. #define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
  22. #define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
  23. #define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
  24. #define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
  25. #define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
  26. #define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
  27. #define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
  28. struct brcmstb_gpio_bank {
  29. struct list_head node;
  30. int id;
  31. struct bgpio_chip bgc;
  32. struct brcmstb_gpio_priv *parent_priv;
  33. u32 width;
  34. };
  35. struct brcmstb_gpio_priv {
  36. struct list_head bank_list;
  37. void __iomem *reg_base;
  38. int num_banks;
  39. struct platform_device *pdev;
  40. int gpio_base;
  41. };
  42. #define MAX_GPIO_PER_BANK 32
  43. #define GPIO_BANK(gpio) ((gpio) >> 5)
  44. /* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
  45. #define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
  46. static inline struct brcmstb_gpio_bank *
  47. brcmstb_gpio_gc_to_bank(struct gpio_chip *gc)
  48. {
  49. struct bgpio_chip *bgc = to_bgpio_chip(gc);
  50. return container_of(bgc, struct brcmstb_gpio_bank, bgc);
  51. }
  52. static inline struct brcmstb_gpio_priv *
  53. brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
  54. {
  55. struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
  56. return bank->parent_priv;
  57. }
  58. /* Make sure that the number of banks matches up between properties */
  59. static int brcmstb_gpio_sanity_check_banks(struct device *dev,
  60. struct device_node *np, struct resource *res)
  61. {
  62. int res_num_banks = resource_size(res) / GIO_BANK_SIZE;
  63. int num_banks =
  64. of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
  65. if (res_num_banks != num_banks) {
  66. dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
  67. res_num_banks, num_banks);
  68. return -EINVAL;
  69. } else {
  70. return 0;
  71. }
  72. }
  73. static int brcmstb_gpio_remove(struct platform_device *pdev)
  74. {
  75. struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
  76. struct list_head *pos;
  77. struct brcmstb_gpio_bank *bank;
  78. int ret = 0;
  79. list_for_each(pos, &priv->bank_list) {
  80. bank = list_entry(pos, struct brcmstb_gpio_bank, node);
  81. ret = bgpio_remove(&bank->bgc);
  82. if (ret)
  83. dev_err(&pdev->dev, "gpiochip_remove fail in cleanup");
  84. }
  85. return ret;
  86. }
  87. static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
  88. const struct of_phandle_args *gpiospec, u32 *flags)
  89. {
  90. struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
  91. struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
  92. int offset;
  93. if (gc->of_gpio_n_cells != 2) {
  94. WARN_ON(1);
  95. return -EINVAL;
  96. }
  97. if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
  98. return -EINVAL;
  99. offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
  100. if (offset >= gc->ngpio)
  101. return -EINVAL;
  102. if (unlikely(offset >= bank->width)) {
  103. dev_warn_ratelimited(&priv->pdev->dev,
  104. "Received request for invalid GPIO offset %d\n",
  105. gpiospec->args[0]);
  106. }
  107. if (flags)
  108. *flags = gpiospec->args[1];
  109. return offset;
  110. }
  111. static int brcmstb_gpio_probe(struct platform_device *pdev)
  112. {
  113. struct device *dev = &pdev->dev;
  114. struct device_node *np = dev->of_node;
  115. void __iomem *reg_base;
  116. struct brcmstb_gpio_priv *priv;
  117. struct resource *res;
  118. struct property *prop;
  119. const __be32 *p;
  120. u32 bank_width;
  121. int err;
  122. static int gpio_base;
  123. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  124. if (!priv)
  125. return -ENOMEM;
  126. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  127. reg_base = devm_ioremap_resource(dev, res);
  128. if (IS_ERR(reg_base))
  129. return PTR_ERR(reg_base);
  130. priv->gpio_base = gpio_base;
  131. priv->reg_base = reg_base;
  132. priv->pdev = pdev;
  133. INIT_LIST_HEAD(&priv->bank_list);
  134. if (brcmstb_gpio_sanity_check_banks(dev, np, res))
  135. return -EINVAL;
  136. of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
  137. bank_width) {
  138. struct brcmstb_gpio_bank *bank;
  139. struct bgpio_chip *bgc;
  140. struct gpio_chip *gc;
  141. bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
  142. if (!bank) {
  143. err = -ENOMEM;
  144. goto fail;
  145. }
  146. bank->parent_priv = priv;
  147. bank->id = priv->num_banks;
  148. if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
  149. dev_err(dev, "Invalid bank width %d\n", bank_width);
  150. goto fail;
  151. } else {
  152. bank->width = bank_width;
  153. }
  154. /*
  155. * Regs are 4 bytes wide, have data reg, no set/clear regs,
  156. * and direction bits have 0 = output and 1 = input
  157. */
  158. bgc = &bank->bgc;
  159. err = bgpio_init(bgc, dev, 4,
  160. reg_base + GIO_DATA(bank->id),
  161. NULL, NULL, NULL,
  162. reg_base + GIO_IODIR(bank->id), 0);
  163. if (err) {
  164. dev_err(dev, "bgpio_init() failed\n");
  165. goto fail;
  166. }
  167. gc = &bgc->gc;
  168. gc->of_node = np;
  169. gc->owner = THIS_MODULE;
  170. gc->label = np->full_name;
  171. gc->base = gpio_base;
  172. gc->of_gpio_n_cells = 2;
  173. gc->of_xlate = brcmstb_gpio_of_xlate;
  174. /* not all ngpio lines are valid, will use bank width later */
  175. gc->ngpio = MAX_GPIO_PER_BANK;
  176. err = gpiochip_add(gc);
  177. if (err) {
  178. dev_err(dev, "Could not add gpiochip for bank %d\n",
  179. bank->id);
  180. goto fail;
  181. }
  182. gpio_base += gc->ngpio;
  183. dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
  184. gc->base, gc->ngpio, bank->width);
  185. /* Everything looks good, so add bank to list */
  186. list_add(&bank->node, &priv->bank_list);
  187. priv->num_banks++;
  188. }
  189. dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
  190. priv->num_banks, priv->gpio_base, gpio_base - 1);
  191. platform_set_drvdata(pdev, priv);
  192. return 0;
  193. fail:
  194. (void) brcmstb_gpio_remove(pdev);
  195. return err;
  196. }
  197. static const struct of_device_id brcmstb_gpio_of_match[] = {
  198. { .compatible = "brcm,brcmstb-gpio" },
  199. {},
  200. };
  201. MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match);
  202. static struct platform_driver brcmstb_gpio_driver = {
  203. .driver = {
  204. .name = "brcmstb-gpio",
  205. .of_match_table = brcmstb_gpio_of_match,
  206. },
  207. .probe = brcmstb_gpio_probe,
  208. .remove = brcmstb_gpio_remove,
  209. };
  210. module_platform_driver(brcmstb_gpio_driver);
  211. MODULE_AUTHOR("Gregory Fong");
  212. MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO");
  213. MODULE_LICENSE("GPL v2");