gpio-creg-snps.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // SPDX-License-Identifier: GPL-2.0+
  2. //
  3. // Synopsys CREG (Control REGisters) GPIO driver
  4. //
  5. // Copyright (C) 2018 Synopsys
  6. // Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
  7. #include <linux/gpio/driver.h>
  8. #include <linux/io.h>
  9. #include <linux/of.h>
  10. #include <linux/of_platform.h>
  11. #define MAX_GPIO 32
  12. struct creg_layout {
  13. u8 ngpio;
  14. u8 shift[MAX_GPIO];
  15. u8 on[MAX_GPIO];
  16. u8 off[MAX_GPIO];
  17. u8 bit_per_gpio[MAX_GPIO];
  18. };
  19. struct creg_gpio {
  20. struct gpio_chip gc;
  21. void __iomem *regs;
  22. spinlock_t lock;
  23. const struct creg_layout *layout;
  24. };
  25. static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
  26. {
  27. struct creg_gpio *hcg = gpiochip_get_data(gc);
  28. const struct creg_layout *layout = hcg->layout;
  29. u32 reg, reg_shift, value;
  30. unsigned long flags;
  31. int i;
  32. value = val ? hcg->layout->on[offset] : hcg->layout->off[offset];
  33. reg_shift = layout->shift[offset];
  34. for (i = 0; i < offset; i++)
  35. reg_shift += layout->bit_per_gpio[i] + layout->shift[i];
  36. spin_lock_irqsave(&hcg->lock, flags);
  37. reg = readl(hcg->regs);
  38. reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift);
  39. reg |= (value << reg_shift);
  40. writel(reg, hcg->regs);
  41. spin_unlock_irqrestore(&hcg->lock, flags);
  42. }
  43. static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
  44. {
  45. creg_gpio_set(gc, offset, val);
  46. return 0;
  47. }
  48. static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg,
  49. int i)
  50. {
  51. const struct creg_layout *layout = hcg->layout;
  52. if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8)
  53. return -EINVAL;
  54. /* Check that on value fits its placeholder */
  55. if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i])
  56. return -EINVAL;
  57. /* Check that off value fits its placeholder */
  58. if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i])
  59. return -EINVAL;
  60. if (layout->on[i] == layout->off[i])
  61. return -EINVAL;
  62. return 0;
  63. }
  64. static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg,
  65. u32 ngpios)
  66. {
  67. u32 reg_len = 0;
  68. int i;
  69. if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO)
  70. return -EINVAL;
  71. if (ngpios < 1 || ngpios > hcg->layout->ngpio) {
  72. dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio);
  73. return -EINVAL;
  74. }
  75. for (i = 0; i < hcg->layout->ngpio; i++) {
  76. if (creg_gpio_validate_pg(dev, hcg, i))
  77. return -EINVAL;
  78. reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i];
  79. }
  80. /* Check that we fit in 32 bit register */
  81. if (reg_len > 32)
  82. return -EINVAL;
  83. return 0;
  84. }
  85. static const struct creg_layout hsdk_cs_ctl = {
  86. .ngpio = 10,
  87. .shift = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  88. .off = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
  89. .on = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
  90. .bit_per_gpio = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
  91. };
  92. static const struct creg_layout axs10x_flsh_cs_ctl = {
  93. .ngpio = 1,
  94. .shift = { 0 },
  95. .off = { 1 },
  96. .on = { 3 },
  97. .bit_per_gpio = { 2 }
  98. };
  99. static const struct of_device_id creg_gpio_ids[] = {
  100. {
  101. .compatible = "snps,creg-gpio-axs10x",
  102. .data = &axs10x_flsh_cs_ctl
  103. }, {
  104. .compatible = "snps,creg-gpio-hsdk",
  105. .data = &hsdk_cs_ctl
  106. }, { /* sentinel */ }
  107. };
  108. static int creg_gpio_probe(struct platform_device *pdev)
  109. {
  110. const struct of_device_id *match;
  111. struct device *dev = &pdev->dev;
  112. struct creg_gpio *hcg;
  113. u32 ngpios;
  114. int ret;
  115. hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL);
  116. if (!hcg)
  117. return -ENOMEM;
  118. hcg->regs = devm_platform_ioremap_resource(pdev, 0);
  119. if (IS_ERR(hcg->regs))
  120. return PTR_ERR(hcg->regs);
  121. match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
  122. hcg->layout = match->data;
  123. if (!hcg->layout)
  124. return -EINVAL;
  125. ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
  126. if (ret)
  127. return ret;
  128. ret = creg_gpio_validate(dev, hcg, ngpios);
  129. if (ret)
  130. return ret;
  131. spin_lock_init(&hcg->lock);
  132. hcg->gc.label = dev_name(dev);
  133. hcg->gc.base = -1;
  134. hcg->gc.ngpio = ngpios;
  135. hcg->gc.set = creg_gpio_set;
  136. hcg->gc.direction_output = creg_gpio_dir_out;
  137. hcg->gc.of_node = dev->of_node;
  138. ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg);
  139. if (ret)
  140. return ret;
  141. dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios);
  142. return 0;
  143. }
  144. static struct platform_driver creg_gpio_snps_driver = {
  145. .driver = {
  146. .name = "snps-creg-gpio",
  147. .of_match_table = creg_gpio_ids,
  148. },
  149. .probe = creg_gpio_probe,
  150. };
  151. builtin_platform_driver(creg_gpio_snps_driver);