904-drivers-leds-Add-the-IEI-WT61P803-PUZZLE-LED-driver.patch 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. From f3b44eb69cc561cf05d00506dcec0dd9be003ed8 Mon Sep 17 00:00:00 2001
  2. From: Luka Kovacic <luka.kovacic () sartura ! hr>
  3. Date: Tue, 24 Aug 2021 12:44:35 +0000
  4. Subject: [PATCH 4/7] drivers: leds: Add the IEI WT61P803 PUZZLE LED driver
  5. Add support for the IEI WT61P803 PUZZLE LED driver.
  6. Currently only the front panel power LED is supported,
  7. since it is the only LED on this board wired through the
  8. MCU.
  9. The LED is wired directly to the on-board MCU controller
  10. and is toggled using an MCU command.
  11. Support for more LEDs is going to be added in case more
  12. boards implement this microcontroller, as LEDs use many
  13. different GPIOs.
  14. This driver depends on the IEI WT61P803 PUZZLE MFD driver.
  15. Signed-off-by: Luka Kovacic <[email protected]>
  16. Signed-off-by: Pavo Banicevic <[email protected]>
  17. Cc: Luka Perkov <[email protected]>
  18. Cc: Robert Marko <[email protected]>
  19. ---
  20. drivers/leds/Kconfig | 8 ++
  21. drivers/leds/Makefile | 1 +
  22. drivers/leds/leds-iei-wt61p803-puzzle.c | 147 ++++++++++++++++++++++++
  23. 3 files changed, 156 insertions(+)
  24. create mode 100644 drivers/leds/leds-iei-wt61p803-puzzle.c
  25. --- a/drivers/leds/Kconfig
  26. +++ b/drivers/leds/Kconfig
  27. @@ -307,6 +307,14 @@ config LEDS_IPAQ_MICRO
  28. Choose this option if you want to use the notification LED on
  29. Compaq/HP iPAQ h3100 and h3600.
  30. +config LEDS_IEI_WT61P803_PUZZLE
  31. + tristate "LED Support for the IEI WT61P803 PUZZLE MCU"
  32. + depends on LEDS_CLASS
  33. + depends on MFD_IEI_WT61P803_PUZZLE
  34. + help
  35. + This option enables support for LEDs controlled by the IEI WT61P803
  36. + M801 MCU.
  37. +
  38. config LEDS_HP6XX
  39. tristate "LED Support for the HP Jornada 6xx"
  40. depends on LEDS_CLASS
  41. --- a/drivers/leds/Makefile
  42. +++ b/drivers/leds/Makefile
  43. @@ -33,6 +33,7 @@ obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.
  44. obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
  45. obj-$(CONFIG_LEDS_IP30) += leds-ip30.o
  46. obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o
  47. +obj-$(CONFIG_LEDS_IEI_WT61P803_PUZZLE) += leds-iei-wt61p803-puzzle.o
  48. obj-$(CONFIG_LEDS_IS31FL319X) += leds-is31fl319x.o
  49. obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
  50. obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
  51. --- /dev/null
  52. +++ b/drivers/leds/leds-iei-wt61p803-puzzle.c
  53. @@ -0,0 +1,147 @@
  54. +// SPDX-License-Identifier: GPL-2.0-only
  55. +/* IEI WT61P803 PUZZLE MCU LED Driver
  56. + *
  57. + * Copyright (C) 2020 Sartura Ltd.
  58. + * Author: Luka Kovacic <[email protected]>
  59. + */
  60. +
  61. +#include <linux/leds.h>
  62. +#include <linux/mfd/iei-wt61p803-puzzle.h>
  63. +#include <linux/mod_devicetable.h>
  64. +#include <linux/module.h>
  65. +#include <linux/platform_device.h>
  66. +#include <linux/property.h>
  67. +#include <linux/slab.h>
  68. +
  69. +enum iei_wt61p803_puzzle_led_state {
  70. + IEI_LED_OFF = 0x30,
  71. + IEI_LED_ON = 0x31,
  72. + IEI_LED_BLINK_5HZ = 0x32,
  73. + IEI_LED_BLINK_1HZ = 0x33,
  74. +};
  75. +
  76. +/**
  77. + * struct iei_wt61p803_puzzle_led - MCU LED Driver
  78. + * @cdev: LED classdev
  79. + * @mcu: MCU struct pointer
  80. + * @response_buffer Global MCU response buffer
  81. + * @lock: General mutex lock to protect simultaneous R/W access to led_power_state
  82. + * @led_power_state: State of the front panel power LED
  83. + */
  84. +struct iei_wt61p803_puzzle_led {
  85. + struct led_classdev cdev;
  86. + struct iei_wt61p803_puzzle *mcu;
  87. + unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
  88. + struct mutex lock; /* mutex to protect led_power_state */
  89. + int led_power_state;
  90. +};
  91. +
  92. +static inline struct iei_wt61p803_puzzle_led *cdev_to_iei_wt61p803_puzzle_led
  93. + (struct led_classdev *led_cdev)
  94. +{
  95. + return container_of(led_cdev, struct iei_wt61p803_puzzle_led, cdev);
  96. +}
  97. +
  98. +static int iei_wt61p803_puzzle_led_brightness_set_blocking(struct led_classdev *cdev,
  99. + enum led_brightness brightness)
  100. +{
  101. + struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
  102. + unsigned char *resp_buf = priv->response_buffer;
  103. + unsigned char led_power_cmd[5] = {};
  104. + size_t reply_size;
  105. + int ret;
  106. +
  107. + led_power_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
  108. + led_power_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
  109. + led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_POWER;
  110. + led_power_cmd[3] = brightness == LED_OFF ? IEI_LED_OFF : IEI_LED_ON;
  111. +
  112. + ret = iei_wt61p803_puzzle_write_command(priv->mcu, led_power_cmd,
  113. + sizeof(led_power_cmd),
  114. + resp_buf,
  115. + &reply_size);
  116. + if (ret)
  117. + return ret;
  118. +
  119. + if (reply_size != 3)
  120. + return -EIO;
  121. +
  122. + if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
  123. + resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
  124. + resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK))
  125. + return -EIO;
  126. +
  127. + mutex_lock(&priv->lock);
  128. + priv->led_power_state = brightness;
  129. + mutex_unlock(&priv->lock);
  130. +
  131. + return 0;
  132. +}
  133. +
  134. +static enum led_brightness iei_wt61p803_puzzle_led_brightness_get(struct led_classdev *cdev)
  135. +{
  136. + struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
  137. + int led_state;
  138. +
  139. + mutex_lock(&priv->lock);
  140. + led_state = priv->led_power_state;
  141. + mutex_unlock(&priv->lock);
  142. +
  143. + return led_state;
  144. +}
  145. +
  146. +static int iei_wt61p803_puzzle_led_probe(struct platform_device *pdev)
  147. +{
  148. + struct device *dev = &pdev->dev;
  149. + struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev->parent);
  150. + struct iei_wt61p803_puzzle_led *priv;
  151. + struct led_init_data init_data = {};
  152. + struct fwnode_handle *child;
  153. + int ret;
  154. +
  155. + if (device_get_child_node_count(dev) != 1)
  156. + return -EINVAL;
  157. +
  158. + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  159. + if (!priv)
  160. + return -ENOMEM;
  161. +
  162. + priv->mcu = mcu;
  163. + priv->led_power_state = 1;
  164. + mutex_init(&priv->lock);
  165. + dev_set_drvdata(dev, priv);
  166. +
  167. + child = device_get_next_child_node(dev, NULL);
  168. + init_data.fwnode = child;
  169. +
  170. + priv->cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
  171. + priv->cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
  172. + priv->cdev.max_brightness = 1;
  173. +
  174. + ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
  175. + if (ret)
  176. + dev_err(dev, "Could not register LED\n");
  177. +
  178. + fwnode_handle_put(child);
  179. + return ret;
  180. +}
  181. +
  182. +static const struct of_device_id iei_wt61p803_puzzle_led_of_match[] = {
  183. + { .compatible = "iei,wt61p803-puzzle-leds" },
  184. + { }
  185. +};
  186. +MODULE_DEVICE_TABLE(of, iei_wt61p803_puzzle_led_of_match);
  187. +
  188. +static struct platform_driver iei_wt61p803_puzzle_led_driver = {
  189. + .driver = {
  190. + .name = "iei-wt61p803-puzzle-led",
  191. + .of_match_table = iei_wt61p803_puzzle_led_of_match,
  192. + },
  193. + .probe = iei_wt61p803_puzzle_led_probe,
  194. +};
  195. +module_platform_driver(iei_wt61p803_puzzle_led_driver);
  196. +
  197. +MODULE_DESCRIPTION("IEI WT61P803 PUZZLE front panel LED driver");
  198. +MODULE_AUTHOR("Luka Kovacic <[email protected]>");
  199. +MODULE_LICENSE("GPL v2");
  200. +MODULE_ALIAS("platform:leds-iei-wt61p803-puzzle");