1 --- a/drivers/leds/leds-iei-wt61p803-puzzle.c
2 +++ b/drivers/leds/leds-iei-wt61p803-puzzle.c
4 #include <linux/mfd/iei-wt61p803-puzzle.h>
5 #include <linux/mod_devicetable.h>
6 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/property.h>
10 #include <linux/slab.h>
12 +#define IEI_LEDS_MAX 4
14 enum iei_wt61p803_puzzle_led_state {
17 @@ -34,6 +37,9 @@ struct iei_wt61p803_puzzle_led {
18 unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
19 struct mutex lock; /* mutex to protect led_power_state */
26 static inline struct iei_wt61p803_puzzle_led *cdev_to_iei_wt61p803_puzzle_led
27 @@ -51,10 +57,20 @@ static int iei_wt61p803_puzzle_led_brigh
31 + mutex_lock(&priv->lock);
32 + if (priv->blinking) {
33 + if (brightness == LED_OFF)
34 + priv->blinking = false;
38 + mutex_unlock(&priv->lock);
40 led_power_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
41 led_power_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
42 - led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_POWER;
43 - led_power_cmd[3] = brightness == LED_OFF ? IEI_LED_OFF : IEI_LED_ON;
44 + led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv->id);
45 + led_power_cmd[3] = ((brightness == LED_OFF) ^ priv->active_low) ?
46 + IEI_LED_OFF : IEI_LED_ON;
48 ret = iei_wt61p803_puzzle_write_command(priv->mcu, led_power_cmd,
49 sizeof(led_power_cmd),
50 @@ -90,39 +106,164 @@ static enum led_brightness iei_wt61p803_
54 +static int iei_wt61p803_puzzle_led_set_blink(struct led_classdev *cdev,
55 + unsigned long *delay_on,
56 + unsigned long *delay_off)
58 + struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
59 + unsigned char led_blink_cmd[5] = {};
60 + unsigned char resp_buf[IEI_WT61P803_PUZZLE_BUF_SIZE];
65 + if (!*delay_on && !*delay_off) {
70 + /* minimum delay for soft-driven blinking is 50ms to keep load low */
74 + if (*delay_off < 50)
77 + if (*delay_on != *delay_off)
80 + /* aggressively offload blinking to hardware, if possible */
81 + if (*delay_on < 100) {
83 + } else if (*delay_on < 200) {
86 + } else if (*delay_on <= 500) {
93 + led_blink_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
94 + led_blink_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
95 + led_blink_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv->id);
96 + led_blink_cmd[3] = (*delay_on == 100)?IEI_LED_BLINK_5HZ:IEI_LED_BLINK_1HZ;
98 + ret = iei_wt61p803_puzzle_write_command(priv->mcu, led_blink_cmd,
99 + sizeof(led_blink_cmd),
106 + if (reply_size != 3)
109 + if (!(resp_buf[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
110 + resp_buf[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
111 + resp_buf[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK))
114 + mutex_lock(&priv->lock);
115 + priv->blinking = true;
116 + mutex_unlock(&priv->lock);
121 +static int iei_wt61p803_puzzle_led_set_dt_default(struct led_classdev *cdev,
122 + struct device_node *np)
127 + state = of_get_property(np, "default-state", NULL);
129 + if (!strcmp(state, "on")) {
131 + iei_wt61p803_puzzle_led_brightness_set_blocking(
132 + cdev, cdev->max_brightness);
134 + ret = iei_wt61p803_puzzle_led_brightness_set_blocking(
142 static int iei_wt61p803_puzzle_led_probe(struct platform_device *pdev)
144 struct device *dev = &pdev->dev;
145 + struct device_node *np = dev_of_node(dev);
146 + struct device_node *child;
147 struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev->parent);
148 struct iei_wt61p803_puzzle_led *priv;
149 - struct led_init_data init_data = {};
150 - struct fwnode_handle *child;
154 - if (device_get_child_node_count(dev) != 1)
155 + if (device_get_child_node_count(dev) > IEI_LEDS_MAX)
158 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
163 - priv->led_power_state = 1;
164 - mutex_init(&priv->lock);
165 - dev_set_drvdata(dev, priv);
167 - child = device_get_next_child_node(dev, NULL);
168 - init_data.fwnode = child;
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 + for_each_available_child_of_node(np, child) {
174 + struct led_init_data init_data = {};
176 - ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
178 - dev_err(dev, "Could not register LED\n");
179 + ret = of_property_read_u32(child, "reg", ®);
181 + dev_err(dev, "Failed to read led 'reg' property\n");
182 + goto put_child_node;
185 + if (reg > IEI_LEDS_MAX) {
186 + dev_err(dev, "Invalid led reg %u\n", reg);
188 + goto put_child_node;
191 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
194 + goto put_child_node;
197 + mutex_init(&priv->lock);
199 + dev_set_drvdata(dev, priv);
201 + if (of_property_read_bool(child, "active-low"))
202 + priv->active_low = true;
206 + priv->led_power_state = 1;
207 + priv->blinking = false;
208 + init_data.fwnode = of_fwnode_handle(child);
210 + priv->cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
211 + priv->cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
212 + priv->cdev.blink_set = iei_wt61p803_puzzle_led_set_blink;
214 + priv->cdev.max_brightness = 1;
216 + ret = iei_wt61p803_puzzle_led_set_dt_default(&priv->cdev, child);
218 + dev_err(dev, "Could apply default from DT\n");
219 + goto put_child_node;
222 + ret = devm_led_classdev_register_ext(dev, &priv->cdev, &init_data);
224 + dev_err(dev, "Could not register LED\n");
225 + goto put_child_node;
231 - fwnode_handle_put(child);
233 + of_node_put(child);
237 --- a/include/linux/mfd/iei-wt61p803-puzzle.h
238 +++ b/include/linux/mfd/iei-wt61p803-puzzle.h
240 #define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_POWER_LOSS 0x41 /* A */
242 #define IEI_WT61P803_PUZZLE_CMD_LED 0x52 /* R */
243 -#define IEI_WT61P803_PUZZLE_CMD_LED_POWER 0x31 /* 1 */
244 +#define IEI_WT61P803_PUZZLE_CMD_LED_SET(n) (0x30 | (n))
246 #define IEI_WT61P803_PUZZLE_CMD_TEMP 0x54 /* T */
247 #define IEI_WT61P803_PUZZLE_CMD_TEMP_ALL 0x41 /* A */