led_bcm6858.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019 Philippe Reynes <philippe.reynes@softathome.com>
  4. *
  5. * based on:
  6. * drivers/led/led_bcm6328.c
  7. * drivers/led/led_bcm6358.c
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <errno.h>
  12. #include <led.h>
  13. #include <asm/io.h>
  14. #include <dm/lists.h>
  15. #define LEDS_MAX 32
  16. #define LEDS_WAIT 100
  17. /* LED Mode register */
  18. #define LED_MODE_REG 0x0
  19. #define LED_MODE_OFF 0
  20. #define LED_MODE_ON 1
  21. #define LED_MODE_MASK 1
  22. /* LED Controller Global settings register */
  23. #define LED_CTRL_REG 0x00
  24. #define LED_CTRL_MASK 0x1f
  25. #define LED_CTRL_LED_TEST_MODE BIT(0)
  26. #define LED_CTRL_SERIAL_LED_DATA_PPOL BIT(1)
  27. #define LED_CTRL_SERIAL_LED_CLK_POL BIT(2)
  28. #define LED_CTRL_SERIAL_LED_EN_POL BIT(3)
  29. #define LED_CTRL_SERIAL_LED_MSB_FIRST BIT(4)
  30. /* LED Controller IP LED source select register */
  31. #define LED_HW_LED_EN_REG 0x08
  32. /* LED Flash control register0 */
  33. #define LED_FLASH_RATE_CONTROL_REG0 0x10
  34. /* Soft LED input register */
  35. #define LED_SW_LED_IP_REG 0xb8
  36. /* Soft LED input polarity register */
  37. #define LED_SW_LED_IP_PPOL_REG 0xbc
  38. struct bcm6858_led_priv {
  39. void __iomem *regs;
  40. u8 pin;
  41. };
  42. #ifdef CONFIG_LED_BLINK
  43. /*
  44. * The value for flash rate are:
  45. * 0 : no blinking
  46. * 1 : rate is 25 Hz => 40 ms (period)
  47. * 2 : rate is 12.5 Hz => 80 ms (period)
  48. * 3 : rate is 6.25 Hz => 160 ms (period)
  49. * 4 : rate is 3.125 Hz => 320 ms (period)
  50. * 5 : rate is 1.5625 Hz => 640 ms (period)
  51. * 6 : rate is 0.7815 Hz => 1280 ms (period)
  52. * 7 : rate is 0.390625 Hz => 2560 ms (period)
  53. */
  54. static const int bcm6858_flash_rate[8] = {
  55. 0, 40, 80, 160, 320, 640, 1280, 2560
  56. };
  57. static u32 bcm6858_flash_rate_value(int period_ms)
  58. {
  59. unsigned long value = 7;
  60. int i;
  61. for (i = 0; i < ARRAY_SIZE(bcm6858_flash_rate); i++) {
  62. if (period_ms <= bcm6858_flash_rate[i]) {
  63. value = i;
  64. break;
  65. }
  66. }
  67. return value;
  68. }
  69. static int bcm6858_led_set_period(struct udevice *dev, int period_ms)
  70. {
  71. struct bcm6858_led_priv *priv = dev_get_priv(dev);
  72. u32 offset, shift, mask, value;
  73. offset = (priv->pin / 8) * 4;
  74. shift = (priv->pin % 8) * 4;
  75. mask = 0x7 << shift;
  76. value = bcm6858_flash_rate_value(period_ms) << shift;
  77. clrbits_32(priv->regs + LED_FLASH_RATE_CONTROL_REG0 + offset, mask);
  78. setbits_32(priv->regs + LED_FLASH_RATE_CONTROL_REG0 + offset, value);
  79. return 0;
  80. }
  81. #endif
  82. static enum led_state_t bcm6858_led_get_state(struct udevice *dev)
  83. {
  84. struct bcm6858_led_priv *priv = dev_get_priv(dev);
  85. enum led_state_t state = LEDST_OFF;
  86. u32 sw_led_ip;
  87. sw_led_ip = readl(priv->regs + LED_SW_LED_IP_REG);
  88. if (sw_led_ip & (1 << priv->pin))
  89. state = LEDST_ON;
  90. return state;
  91. }
  92. static int bcm6858_led_set_state(struct udevice *dev, enum led_state_t state)
  93. {
  94. struct bcm6858_led_priv *priv = dev_get_priv(dev);
  95. switch (state) {
  96. case LEDST_OFF:
  97. clrbits_32(priv->regs + LED_SW_LED_IP_REG, (1 << priv->pin));
  98. #ifdef CONFIG_LED_BLINK
  99. bcm6858_led_set_period(dev, 0);
  100. #endif
  101. break;
  102. case LEDST_ON:
  103. setbits_32(priv->regs + LED_SW_LED_IP_REG, (1 << priv->pin));
  104. #ifdef CONFIG_LED_BLINK
  105. bcm6858_led_set_period(dev, 0);
  106. #endif
  107. break;
  108. case LEDST_TOGGLE:
  109. if (bcm6858_led_get_state(dev) == LEDST_OFF)
  110. return bcm6858_led_set_state(dev, LEDST_ON);
  111. else
  112. return bcm6858_led_set_state(dev, LEDST_OFF);
  113. break;
  114. #ifdef CONFIG_LED_BLINK
  115. case LEDST_BLINK:
  116. setbits_32(priv->regs + LED_SW_LED_IP_REG, (1 << priv->pin));
  117. break;
  118. #endif
  119. default:
  120. return -EINVAL;
  121. }
  122. return 0;
  123. }
  124. static const struct led_ops bcm6858_led_ops = {
  125. .get_state = bcm6858_led_get_state,
  126. .set_state = bcm6858_led_set_state,
  127. #ifdef CONFIG_LED_BLINK
  128. .set_period = bcm6858_led_set_period,
  129. #endif
  130. };
  131. static int bcm6858_led_probe(struct udevice *dev)
  132. {
  133. struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
  134. /* Top-level LED node */
  135. if (!uc_plat->label) {
  136. void __iomem *regs;
  137. u32 set_bits = 0;
  138. regs = dev_remap_addr(dev);
  139. if (!regs)
  140. return -EINVAL;
  141. if (dev_read_bool(dev, "brcm,serial-led-msb-first"))
  142. set_bits |= LED_CTRL_SERIAL_LED_MSB_FIRST;
  143. if (dev_read_bool(dev, "brcm,serial-led-en-pol"))
  144. set_bits |= LED_CTRL_SERIAL_LED_EN_POL;
  145. if (dev_read_bool(dev, "brcm,serial-led-clk-pol"))
  146. set_bits |= LED_CTRL_SERIAL_LED_CLK_POL;
  147. if (dev_read_bool(dev, "brcm,serial-led-data-ppol"))
  148. set_bits |= LED_CTRL_SERIAL_LED_DATA_PPOL;
  149. if (dev_read_bool(dev, "brcm,led-test-mode"))
  150. set_bits |= LED_CTRL_LED_TEST_MODE;
  151. clrsetbits_32(regs + LED_CTRL_REG, ~0, set_bits);
  152. } else {
  153. struct bcm6858_led_priv *priv = dev_get_priv(dev);
  154. void __iomem *regs;
  155. unsigned int pin;
  156. regs = dev_remap_addr(dev_get_parent(dev));
  157. if (!regs)
  158. return -EINVAL;
  159. pin = dev_read_u32_default(dev, "reg", LEDS_MAX);
  160. if (pin >= LEDS_MAX)
  161. return -EINVAL;
  162. priv->regs = regs;
  163. priv->pin = pin;
  164. /* this led is managed by software */
  165. clrbits_32(regs + LED_HW_LED_EN_REG, 1 << pin);
  166. /* configure the polarity */
  167. if (dev_read_bool(dev, "active-low"))
  168. clrbits_32(regs + LED_SW_LED_IP_PPOL_REG, 1 << pin);
  169. else
  170. setbits_32(regs + LED_SW_LED_IP_PPOL_REG, 1 << pin);
  171. }
  172. return 0;
  173. }
  174. static int bcm6858_led_bind(struct udevice *parent)
  175. {
  176. ofnode node;
  177. dev_for_each_subnode(node, parent) {
  178. struct led_uc_plat *uc_plat;
  179. struct udevice *dev;
  180. const char *label;
  181. int ret;
  182. label = ofnode_read_string(node, "label");
  183. if (!label) {
  184. debug("%s: node %s has no label\n", __func__,
  185. ofnode_get_name(node));
  186. return -EINVAL;
  187. }
  188. ret = device_bind_driver_to_node(parent, "bcm6858-led",
  189. ofnode_get_name(node),
  190. node, &dev);
  191. if (ret)
  192. return ret;
  193. uc_plat = dev_get_uclass_platdata(dev);
  194. uc_plat->label = label;
  195. }
  196. return 0;
  197. }
  198. static const struct udevice_id bcm6858_led_ids[] = {
  199. { .compatible = "brcm,bcm6858-leds" },
  200. { /* sentinel */ }
  201. };
  202. U_BOOT_DRIVER(bcm6858_led) = {
  203. .name = "bcm6858-led",
  204. .id = UCLASS_LED,
  205. .of_match = bcm6858_led_ids,
  206. .bind = bcm6858_led_bind,
  207. .probe = bcm6858_led_probe,
  208. .priv_auto_alloc_size = sizeof(struct bcm6858_led_priv),
  209. .ops = &bcm6858_led_ops,
  210. };