leds-smartrg-system.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/delay.h>
  3. #include <linux/i2c.h>
  4. #include <linux/init.h>
  5. #include <linux/leds.h>
  6. #include <linux/module.h>
  7. #include <linux/mutex.h>
  8. #include <linux/of.h>
  9. #include <linux/version.h>
  10. /**
  11. * Driver for SmartRG RGBW LED microcontroller.
  12. * RGBW LED is connected to a Holtek HT45F0062 that is on the I2C bus.
  13. *
  14. */
  15. struct srg_led_ctrl;
  16. struct srg_led {
  17. u8 index;
  18. struct led_classdev led;
  19. struct srg_led_ctrl *ctrl;
  20. };
  21. struct srg_led_ctrl {
  22. struct mutex lock;
  23. struct i2c_client *client;
  24. struct srg_led channel[4];
  25. u8 control[5];
  26. };
  27. static int
  28. srg_led_i2c_write(struct srg_led_ctrl *sysled_ctrl, u8 reg, u8 value)
  29. {
  30. return i2c_smbus_write_byte_data(sysled_ctrl->client, reg, value);
  31. }
  32. /*
  33. * MC LED Command: 0 = OFF, 1 = ON, 2 = Flash, 3 = Pulse, 4 = Blink
  34. * */
  35. static int
  36. srg_led_control_sync(struct srg_led_ctrl *sysled_ctrl)
  37. {
  38. int i, ret;
  39. for (i = 1; i < 5; i++) {
  40. ret = srg_led_i2c_write(sysled_ctrl, i, sysled_ctrl->control[i]);
  41. if (ret)
  42. break;
  43. }
  44. return ret;
  45. }
  46. /*
  47. * This function overrides the led driver timer trigger to offload
  48. * flashing to the micro-controller. The negative effect of this
  49. * is the inability to configure the delay_on and delay_off periods.
  50. *
  51. * */
  52. static int
  53. srg_led_set_pulse(struct led_classdev *led_cdev,
  54. unsigned long *delay_on,
  55. unsigned long *delay_off)
  56. {
  57. struct srg_led *sysled = container_of(led_cdev, struct srg_led, led);
  58. struct srg_led_ctrl *sysled_ctrl = sysled->ctrl;
  59. bool blinking = false, pulsing = false;
  60. u8 cbyte;
  61. int ret;
  62. if (delay_on && delay_off && (*delay_on > 100) && (*delay_on <= 500)) {
  63. pulsing = true;
  64. *delay_on = 500;
  65. *delay_off = 500;
  66. } else if (delay_on && delay_off && (*delay_on >= 50) && (*delay_on <= 100)) {
  67. blinking = true;
  68. *delay_on = 50;
  69. *delay_off = 50;
  70. }
  71. cbyte = pulsing ? 3 : blinking ? 2 : 0;
  72. mutex_lock(&sysled_ctrl->lock);
  73. ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4,
  74. (blinking || pulsing) ? 255 : 0);
  75. if (!ret) {
  76. sysled_ctrl->control[sysled->index] = cbyte;
  77. ret = srg_led_control_sync(sysled_ctrl);
  78. }
  79. mutex_unlock(&sysled_ctrl->lock);
  80. return !cbyte;
  81. }
  82. static int
  83. srg_led_set_brightness(struct led_classdev *led_cdev,
  84. enum led_brightness value)
  85. {
  86. struct srg_led *sysled = container_of(led_cdev, struct srg_led, led);
  87. struct srg_led_ctrl *sysled_ctrl = sysled->ctrl;
  88. int ret;
  89. mutex_lock(&sysled_ctrl->lock);
  90. ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4, value);
  91. if (!ret) {
  92. sysled_ctrl->control[sysled->index] = !!value;
  93. ret = srg_led_control_sync(sysled_ctrl);
  94. }
  95. mutex_unlock(&sysled_ctrl->lock);
  96. return ret;
  97. }
  98. static int
  99. srg_led_init_led(struct srg_led_ctrl *sysled_ctrl, struct device_node *np)
  100. {
  101. struct led_init_data init_data = {};
  102. struct led_classdev *led_cdev;
  103. struct srg_led *sysled;
  104. int index, ret;
  105. if (!np)
  106. return -ENOENT;
  107. ret = of_property_read_u32(np, "reg", &index);
  108. if (ret) {
  109. dev_err(&sysled_ctrl->client->dev,
  110. "srg_led_init_led: no reg defined in np!\n");
  111. return ret;
  112. }
  113. if (index < 1 || index > 4)
  114. return -EINVAL;
  115. sysled = &sysled_ctrl->channel[index - 1];
  116. led_cdev = &sysled->led;
  117. sysled->index = index;
  118. sysled->ctrl = sysled_ctrl;
  119. init_data.fwnode = of_fwnode_handle(np);
  120. led_cdev->name = of_get_property(np, "label", NULL) ? : np->name;
  121. led_cdev->brightness = LED_OFF;
  122. led_cdev->max_brightness = LED_FULL;
  123. led_cdev->brightness_set_blocking = srg_led_set_brightness;
  124. led_cdev->blink_set = srg_led_set_pulse;
  125. srg_led_i2c_write(sysled_ctrl, index + 4, 0);
  126. ret = devm_led_classdev_register_ext(&sysled_ctrl->client->dev,
  127. led_cdev, &init_data);
  128. if (ret) {
  129. dev_err(&sysled_ctrl->client->dev,
  130. "srg_led_init_led: led register %s error ret %d!n",
  131. led_cdev->name, ret);
  132. return ret;
  133. }
  134. return 0;
  135. }
  136. static int
  137. #if LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0)
  138. srg_led_probe(struct i2c_client *client, const struct i2c_device_id *id)
  139. #else
  140. srg_led_probe(struct i2c_client *client)
  141. #endif
  142. {
  143. struct device_node *np = client->dev.of_node, *child;
  144. struct srg_led_ctrl *sysled_ctrl;
  145. sysled_ctrl = devm_kzalloc(&client->dev, sizeof(*sysled_ctrl), GFP_KERNEL);
  146. if (!sysled_ctrl)
  147. return -ENOMEM;
  148. sysled_ctrl->client = client;
  149. mutex_init(&sysled_ctrl->lock);
  150. i2c_set_clientdata(client, sysled_ctrl);
  151. for_each_child_of_node(np, child) {
  152. if (srg_led_init_led(sysled_ctrl, child))
  153. continue;
  154. msleep(5);
  155. }
  156. return srg_led_control_sync(sysled_ctrl);;
  157. }
  158. static void srg_led_disable(struct i2c_client *client)
  159. {
  160. struct srg_led_ctrl *sysled_ctrl = i2c_get_clientdata(client);
  161. int i;
  162. for (i = 1; i < 10; i++)
  163. srg_led_i2c_write(sysled_ctrl, i, 0);
  164. }
  165. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)
  166. static void
  167. #else
  168. static int
  169. #endif
  170. srg_led_remove(struct i2c_client *client)
  171. {
  172. struct srg_led_ctrl *sysled_ctrl = i2c_get_clientdata(client);
  173. srg_led_disable(client);
  174. mutex_destroy(&sysled_ctrl->lock);
  175. #if LINUX_VERSION_CODE < KERNEL_VERSION(5,16,0)
  176. return 0;
  177. #endif
  178. }
  179. static const struct i2c_device_id srg_led_id[] = {
  180. { "srg-sysled", 0 },
  181. { }
  182. };
  183. MODULE_DEVICE_TABLE(i2c, srg_led_id);
  184. static const struct of_device_id of_srg_led_match[] = {
  185. { .compatible = "srg,sysled", },
  186. {},
  187. };
  188. MODULE_DEVICE_TABLE(of, of_srg_led_match);
  189. static struct i2c_driver srg_sysled_driver = {
  190. .driver = {
  191. .name = "srg-sysled",
  192. .of_match_table = of_srg_led_match,
  193. },
  194. .probe = srg_led_probe,
  195. .remove = srg_led_remove,
  196. .id_table = srg_led_id,
  197. };
  198. module_i2c_driver(srg_sysled_driver);
  199. MODULE_DESCRIPTION("SmartRG system LED driver");
  200. MODULE_AUTHOR("Shen Loh <[email protected]>");
  201. MODULE_AUTHOR("Daniel Golle <[email protected]>");
  202. MODULE_LICENSE("GPL v2");