brcmstb-usb-pinmap.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2020, Broadcom */
  3. #include <linux/init.h>
  4. #include <linux/types.h>
  5. #include <linux/module.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/io.h>
  9. #include <linux/device.h>
  10. #include <linux/of.h>
  11. #include <linux/kernel.h>
  12. #include <linux/kdebug.h>
  13. #include <linux/gpio/consumer.h>
  14. struct out_pin {
  15. u32 enable_mask;
  16. u32 value_mask;
  17. u32 changed_mask;
  18. u32 clr_changed_mask;
  19. struct gpio_desc *gpiod;
  20. const char *name;
  21. };
  22. struct in_pin {
  23. u32 enable_mask;
  24. u32 value_mask;
  25. struct gpio_desc *gpiod;
  26. const char *name;
  27. struct brcmstb_usb_pinmap_data *pdata;
  28. };
  29. struct brcmstb_usb_pinmap_data {
  30. void __iomem *regs;
  31. int in_count;
  32. struct in_pin *in_pins;
  33. int out_count;
  34. struct out_pin *out_pins;
  35. };
  36. static void pinmap_set(void __iomem *reg, u32 mask)
  37. {
  38. u32 val;
  39. val = readl(reg);
  40. val |= mask;
  41. writel(val, reg);
  42. }
  43. static void pinmap_unset(void __iomem *reg, u32 mask)
  44. {
  45. u32 val;
  46. val = readl(reg);
  47. val &= ~mask;
  48. writel(val, reg);
  49. }
  50. static void sync_in_pin(struct in_pin *pin)
  51. {
  52. u32 val;
  53. val = gpiod_get_value(pin->gpiod);
  54. if (val)
  55. pinmap_set(pin->pdata->regs, pin->value_mask);
  56. else
  57. pinmap_unset(pin->pdata->regs, pin->value_mask);
  58. }
  59. /*
  60. * Interrupt from override register, propagate from override bit
  61. * to GPIO.
  62. */
  63. static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id)
  64. {
  65. struct brcmstb_usb_pinmap_data *pdata = dev_id;
  66. struct out_pin *pout;
  67. u32 val;
  68. u32 bit;
  69. int x;
  70. pr_debug("%s: reg: 0x%x\n", __func__, readl(pdata->regs));
  71. pout = pdata->out_pins;
  72. for (x = 0; x < pdata->out_count; x++) {
  73. val = readl(pdata->regs);
  74. if (val & pout->changed_mask) {
  75. pinmap_set(pdata->regs, pout->clr_changed_mask);
  76. pinmap_unset(pdata->regs, pout->clr_changed_mask);
  77. bit = val & pout->value_mask;
  78. gpiod_set_value(pout->gpiod, bit ? 1 : 0);
  79. pr_debug("%s: %s bit changed state to %d\n",
  80. __func__, pout->name, bit ? 1 : 0);
  81. }
  82. }
  83. return IRQ_HANDLED;
  84. }
  85. /*
  86. * Interrupt from GPIO, propagate from GPIO to override bit.
  87. */
  88. static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id)
  89. {
  90. struct in_pin *pin = dev_id;
  91. pr_debug("%s: %s pin changed state\n", __func__, pin->name);
  92. sync_in_pin(pin);
  93. return IRQ_HANDLED;
  94. }
  95. static void get_pin_counts(struct device_node *dn, int *in_count,
  96. int *out_count)
  97. {
  98. int in;
  99. int out;
  100. *in_count = 0;
  101. *out_count = 0;
  102. in = of_property_count_strings(dn, "brcm,in-functions");
  103. if (in < 0)
  104. return;
  105. out = of_property_count_strings(dn, "brcm,out-functions");
  106. if (out < 0)
  107. return;
  108. *in_count = in;
  109. *out_count = out;
  110. }
  111. static int parse_pins(struct device *dev, struct device_node *dn,
  112. struct brcmstb_usb_pinmap_data *pdata)
  113. {
  114. struct out_pin *pout;
  115. struct in_pin *pin;
  116. int index;
  117. int res;
  118. int x;
  119. pin = pdata->in_pins;
  120. for (x = 0, index = 0; x < pdata->in_count; x++) {
  121. pin->gpiod = devm_gpiod_get_index(dev, "in", x, GPIOD_IN);
  122. if (IS_ERR(pin->gpiod)) {
  123. dev_err(dev, "Error getting gpio %s\n", pin->name);
  124. return PTR_ERR(pin->gpiod);
  125. }
  126. res = of_property_read_string_index(dn, "brcm,in-functions", x,
  127. &pin->name);
  128. if (res < 0) {
  129. dev_err(dev, "Error getting brcm,in-functions for %s\n",
  130. pin->name);
  131. return res;
  132. }
  133. res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
  134. &pin->enable_mask);
  135. if (res < 0) {
  136. dev_err(dev, "Error getting 1st brcm,in-masks for %s\n",
  137. pin->name);
  138. return res;
  139. }
  140. res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
  141. &pin->value_mask);
  142. if (res < 0) {
  143. dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n",
  144. pin->name);
  145. return res;
  146. }
  147. pin->pdata = pdata;
  148. pin++;
  149. }
  150. pout = pdata->out_pins;
  151. for (x = 0, index = 0; x < pdata->out_count; x++) {
  152. pout->gpiod = devm_gpiod_get_index(dev, "out", x,
  153. GPIOD_OUT_HIGH);
  154. if (IS_ERR(pout->gpiod)) {
  155. dev_err(dev, "Error getting gpio %s\n", pin->name);
  156. return PTR_ERR(pout->gpiod);
  157. }
  158. res = of_property_read_string_index(dn, "brcm,out-functions", x,
  159. &pout->name);
  160. if (res < 0) {
  161. dev_err(dev, "Error getting brcm,out-functions for %s\n",
  162. pout->name);
  163. return res;
  164. }
  165. res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
  166. &pout->enable_mask);
  167. if (res < 0) {
  168. dev_err(dev, "Error getting 1st brcm,out-masks for %s\n",
  169. pout->name);
  170. return res;
  171. }
  172. res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
  173. &pout->value_mask);
  174. if (res < 0) {
  175. dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n",
  176. pout->name);
  177. return res;
  178. }
  179. res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
  180. &pout->changed_mask);
  181. if (res < 0) {
  182. dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n",
  183. pout->name);
  184. return res;
  185. }
  186. res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
  187. &pout->clr_changed_mask);
  188. if (res < 0) {
  189. dev_err(dev, "Error getting 4th out-masks for %s\n",
  190. pout->name);
  191. return res;
  192. }
  193. pout++;
  194. }
  195. return 0;
  196. }
  197. static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata)
  198. {
  199. struct out_pin *pout;
  200. struct in_pin *pin;
  201. int val;
  202. int x;
  203. /*
  204. * Enable the override, clear any changed condition and
  205. * propagate the state to the GPIO for all out pins.
  206. */
  207. pout = pdata->out_pins;
  208. for (x = 0; x < pdata->out_count; x++) {
  209. pinmap_set(pdata->regs, pout->enable_mask);
  210. pinmap_set(pdata->regs, pout->clr_changed_mask);
  211. pinmap_unset(pdata->regs, pout->clr_changed_mask);
  212. val = readl(pdata->regs) & pout->value_mask;
  213. gpiod_set_value(pout->gpiod, val ? 1 : 0);
  214. pout++;
  215. }
  216. /* sync and enable all in pins. */
  217. pin = pdata->in_pins;
  218. for (x = 0; x < pdata->in_count; x++) {
  219. sync_in_pin(pin);
  220. pinmap_set(pdata->regs, pin->enable_mask);
  221. pin++;
  222. }
  223. }
  224. static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev)
  225. {
  226. struct device_node *dn = pdev->dev.of_node;
  227. struct brcmstb_usb_pinmap_data *pdata;
  228. struct in_pin *pin;
  229. struct resource *r;
  230. int out_count;
  231. int in_count;
  232. int err;
  233. int irq;
  234. int x;
  235. get_pin_counts(dn, &in_count, &out_count);
  236. if ((in_count + out_count) == 0)
  237. return -EINVAL;
  238. r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  239. if (!r)
  240. return -EINVAL;
  241. pdata = devm_kzalloc(&pdev->dev,
  242. sizeof(*pdata) +
  243. (sizeof(struct in_pin) * in_count) +
  244. (sizeof(struct out_pin) * out_count), GFP_KERNEL);
  245. if (!pdata)
  246. return -ENOMEM;
  247. pdata->in_count = in_count;
  248. pdata->out_count = out_count;
  249. pdata->in_pins = (struct in_pin *)(pdata + 1);
  250. pdata->out_pins = (struct out_pin *)(pdata->in_pins + in_count);
  251. pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
  252. if (!pdata->regs)
  253. return -ENOMEM;
  254. platform_set_drvdata(pdev, pdata);
  255. err = parse_pins(&pdev->dev, dn, pdata);
  256. if (err)
  257. return err;
  258. sync_all_pins(pdata);
  259. if (out_count) {
  260. /* Enable interrupt for out pins */
  261. irq = platform_get_irq(pdev, 0);
  262. if (irq < 0)
  263. return irq;
  264. err = devm_request_irq(&pdev->dev, irq,
  265. brcmstb_usb_pinmap_ovr_isr,
  266. IRQF_TRIGGER_RISING,
  267. pdev->name, pdata);
  268. if (err < 0) {
  269. dev_err(&pdev->dev, "Error requesting IRQ\n");
  270. return err;
  271. }
  272. }
  273. for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) {
  274. irq = gpiod_to_irq(pin->gpiod);
  275. if (irq < 0) {
  276. dev_err(&pdev->dev, "Error getting IRQ for %s pin\n",
  277. pin->name);
  278. return irq;
  279. }
  280. err = devm_request_irq(&pdev->dev, irq,
  281. brcmstb_usb_pinmap_gpio_isr,
  282. IRQF_SHARED | IRQF_TRIGGER_RISING |
  283. IRQF_TRIGGER_FALLING,
  284. pdev->name, pin);
  285. if (err < 0) {
  286. dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n",
  287. pin->name);
  288. return err;
  289. }
  290. }
  291. dev_dbg(&pdev->dev, "Driver probe succeeded\n");
  292. dev_dbg(&pdev->dev, "In pin count: %d, out pin count: %d\n",
  293. pdata->in_count, pdata->out_count);
  294. return 0;
  295. }
  296. static const struct of_device_id brcmstb_usb_pinmap_of_match[] = {
  297. { .compatible = "brcm,usb-pinmap" },
  298. { },
  299. };
  300. static struct platform_driver brcmstb_usb_pinmap_driver = {
  301. .driver = {
  302. .name = "brcm-usb-pinmap",
  303. .of_match_table = brcmstb_usb_pinmap_of_match,
  304. },
  305. };
  306. static int __init brcmstb_usb_pinmap_init(void)
  307. {
  308. return platform_driver_probe(&brcmstb_usb_pinmap_driver,
  309. brcmstb_usb_pinmap_probe);
  310. }
  311. module_init(brcmstb_usb_pinmap_init);
  312. MODULE_AUTHOR("Al Cooper <[email protected]>");
  313. MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
  314. MODULE_LICENSE("GPL");