aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 15:22:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 15:22:41 -0500
commit50081e437872e68300750068754f21d0faac5d86 (patch)
treecf8cf8bcf438c722bddc03482a4190e606984275
parent7b1cd95d65eb3b1e13f8a90eb757e0ea232c7899 (diff)
parent6a836631e303cec7fd9469ae53a4d97d0360eb38 (diff)
Merge tag 'leds_for_4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds
Pull LED updates from Jacek Anaszewski: "New LED class driver: - introduce LM3692x dual string driver New LED trigger: - introduce a NETDEV trigger leds-lp8860: - various fixes to align with LED framework - add regulator enable during init - DT support related improvements Minor fixes and cleanups to the LED class drivers: - leds-pwm - ledtrig-activity - leds-blinkm - leds-as3645a - ledtrig-transient" * tag 'leds_for_4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: leds: ledtrig-transient: Add SPDX license identifiers leds: lp8860: Various fixes to align with LED framework leds: lp8860: Add DT parsing to retrieve the trigger node dt: bindings: lp8860: Add trigger binding to the lp8860 leds: lp8860: Update the dt parsing for LED labeling dt: bindings: lp8860: Update DT label binding dt: bindings: lp8860: Update bindings for lp8860 leds: as3645a: Fix line over 80 characters leds: as3645a: Fix quoted string split warning leds: lm3692x: Introduce LM3692x dual string driver dt: bindings: lm3692x: Add bindings for lm3692x LED driver leds: trigger: Introduce a NETDEV trigger leds: blinkm: avoid uninitialized data use ledtrig-activity: Grammar s/a immediate/an immediate/ leds: pwm: Remove unneeded header file leds: lp8860: Add regulator enable during init leds: lp8860: Fix linuxdoc format for structure
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-netdev45
-rw-r--r--Documentation/devicetree/bindings/leds/leds-lm3692x.txt49
-rw-r--r--Documentation/devicetree/bindings/leds/leds-lp8860.txt32
-rw-r--r--drivers/leds/Kconfig9
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-as3645a.c7
-rw-r--r--drivers/leds/leds-blinkm.c4
-rw-r--r--drivers/leds/leds-lm3692x.c393
-rw-r--r--drivers/leds/leds-lp8860.c66
-rw-r--r--drivers/leds/leds-pwm.c1
-rw-r--r--drivers/leds/trigger/Kconfig9
-rw-r--r--drivers/leds/trigger/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-netdev.c496
-rw-r--r--drivers/leds/trigger/ledtrig-transient.c33
14 files changed, 1091 insertions, 55 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
new file mode 100644
index 000000000000..451af6d6768c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
@@ -0,0 +1,45 @@
1What: /sys/class/leds/<led>/device_name
2Date: Dec 2017
3KernelVersion: 4.16
4Contact: linux-leds@vger.kernel.org
5Description:
6 Specifies the network device name to monitor.
7
8What: /sys/class/leds/<led>/interval
9Date: Dec 2017
10KernelVersion: 4.16
11Contact: linux-leds@vger.kernel.org
12Description:
13 Specifies the duration of the LED blink in milliseconds.
14 Defaults to 50 ms.
15
16What: /sys/class/leds/<led>/link
17Date: Dec 2017
18KernelVersion: 4.16
19Contact: linux-leds@vger.kernel.org
20Description:
21 Signal the link state of the named network device.
22 If set to 0 (default), the LED's normal state is off.
23 If set to 1, the LED's normal state reflects the link state
24 of the named network device.
25 Setting this value also immediately changes the LED state.
26
27What: /sys/class/leds/<led>/tx
28Date: Dec 2017
29KernelVersion: 4.16
30Contact: linux-leds@vger.kernel.org
31Description:
32 Signal transmission of data on the named network device.
33 If set to 0 (default), the LED will not blink on transmission.
34 If set to 1, the LED will blink for the milliseconds specified
35 in interval to signal transmission.
36
37What: /sys/class/leds/<led>/rx
38Date: Dec 2017
39KernelVersion: 4.16
40Contact: linux-leds@vger.kernel.org
41Description:
42 Signal reception of data on the named network device.
43 If set to 0 (default), the LED will not blink on reception.
44 If set to 1, the LED will blink for the milliseconds specified
45 in interval to signal reception.
diff --git a/Documentation/devicetree/bindings/leds/leds-lm3692x.txt b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt
new file mode 100644
index 000000000000..6c9074f84a51
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt
@@ -0,0 +1,49 @@
1* Texas Instruments - LM3692x Highly Efficient White LED Driver
2
3The LM3692x is an ultra-compact, highly efficient,
4white-LED driver designed for LCD display backlighting.
5
6The main difference between the LM36922 and LM36923 is the number of
7LED strings it supports. The LM36922 supports two strings while the LM36923
8supports three strings.
9
10Required properties:
11 - compatible:
12 "ti,lm36922"
13 "ti,lm36923"
14 - reg : I2C slave address
15 - #address-cells : 1
16 - #size-cells : 0
17
18Optional properties:
19 - enable-gpios : gpio pin to enable/disable the device.
20 - vled-supply : LED supply
21
22Required child properties:
23 - reg : 0
24
25Optional child properties:
26 - label : see Documentation/devicetree/bindings/leds/common.txt
27 - linux,default-trigger :
28 see Documentation/devicetree/bindings/leds/common.txt
29
30Example:
31
32led-controller@36 {
33 compatible = "ti,lm3692x";
34 reg = <0x36>;
35 #address-cells = <1>;
36 #size-cells = <0>;
37
38 enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
39 vled-supply = <&vbatt>;
40
41 led@0 {
42 reg = <0>;
43 label = "white:backlight_cluster";
44 linux,default-trigger = "backlight";
45 };
46}
47
48For more product information please see the link below:
49http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt
index aad38dd94d4b..5f0e892ad759 100644
--- a/Documentation/devicetree/bindings/leds/leds-lp8860.txt
+++ b/Documentation/devicetree/bindings/leds/leds-lp8860.txt
@@ -6,23 +6,39 @@ current sinks that can be controlled by a PWM input
6signal, a SPI/I2C master, or both. 6signal, a SPI/I2C master, or both.
7 7
8Required properties: 8Required properties:
9 - compatible: 9 - compatible :
10 "ti,lp8860" 10 "ti,lp8860"
11 - reg - I2C slave address 11 - reg : I2C slave address
12 - label - Used for naming LEDs 12 - #address-cells : 1
13 - #size-cells : 0
13 14
14Optional properties: 15Optional properties:
15 - enable-gpio - gpio pin to enable/disable the device. 16 - enable-gpios : gpio pin to enable (active high)/disable the device.
16 - supply - "vled" - LED supply 17 - vled-supply : LED supply
18
19Required child properties:
20 - reg : 0
21
22Optional child properties:
23 - label : see Documentation/devicetree/bindings/leds/common.txt
24 - linux,default-trigger :
25 see Documentation/devicetree/bindings/leds/common.txt
17 26
18Example: 27Example:
19 28
20leds: leds@6 { 29led-controller@2d {
21 compatible = "ti,lp8860"; 30 compatible = "ti,lp8860";
31 #address-cells = <1>;
32 #size-cells = <0>;
22 reg = <0x2d>; 33 reg = <0x2d>;
23 label = "display_cluster"; 34 enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
24 enable-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>;
25 vled-supply = <&vbatt>; 35 vled-supply = <&vbatt>;
36
37 led@0 {
38 reg = <0>;
39 label = "white:backlight";
40 linux,default-trigger = "backlight";
41 };
26} 42}
27 43
28For more product information please see the link below: 44For more product information please see the link below:
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 318a28fd58fe..3e763d2a0cb3 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -137,6 +137,13 @@ config LEDS_LM3642
137 converter plus 1.5A constant current driver for a high-current 137 converter plus 1.5A constant current driver for a high-current
138 white LED. 138 white LED.
139 139
140config LEDS_LM3692X
141 tristate "LED support for LM3692x Chips"
142 depends on LEDS_CLASS && I2C && OF
143 select REGMAP_I2C
144 help
145 This option enables support for the TI LM3692x family
146 of white LED string drivers used for backlighting.
140 147
141config LEDS_LOCOMO 148config LEDS_LOCOMO
142 tristate "LED Support for Locomo device" 149 tristate "LED Support for Locomo device"
@@ -347,7 +354,7 @@ config LEDS_LP8788
347 354
348config LEDS_LP8860 355config LEDS_LP8860
349 tristate "LED support for the TI LP8860 4 channel LED driver" 356 tristate "LED support for the TI LP8860 4 channel LED driver"
350 depends on LEDS_CLASS && I2C 357 depends on LEDS_CLASS && I2C && OF
351 select REGMAP_I2C 358 select REGMAP_I2C
352 help 359 help
353 If you say yes here you get support for the TI LP8860 4 channel 360 If you say yes here you get support for the TI LP8860 4 channel
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a2a6b5a4f86d..987884a5b9a5 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
74obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o 74obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
75obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o 75obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o
76obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o 76obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
77obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
77 78
78# LED SPI Drivers 79# LED SPI Drivers
79obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o 80obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
index 9a257f969300..f883616d9e60 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/leds-as3645a.c
@@ -360,7 +360,8 @@ static int as3645a_set_flash_brightness(struct led_classdev_flash *fled,
360{ 360{
361 struct as3645a *flash = fled_to_as3645a(fled); 361 struct as3645a *flash = fled_to_as3645a(fled);
362 362
363 flash->flash_current = as3645a_current_to_reg(flash, true, brightness_ua); 363 flash->flash_current = as3645a_current_to_reg(flash, true,
364 brightness_ua);
364 365
365 return as3645a_set_current(flash); 366 return as3645a_set_current(flash);
366} 367}
@@ -455,8 +456,8 @@ static int as3645a_detect(struct as3645a *flash)
455 456
456 /* Verify the chip model and version. */ 457 /* Verify the chip model and version. */
457 if (model != 0x01 || rfu != 0x00) { 458 if (model != 0x01 || rfu != 0x00) {
458 dev_err(dev, "AS3645A not detected " 459 dev_err(dev, "AS3645A not detected (model %d rfu %d)\n",
459 "(model %d rfu %d)\n", model, rfu); 460 model, rfu);
460 return -ENODEV; 461 return -ENODEV;
461 } 462 }
462 463
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index d03ed6b4176b..851c1920b63c 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -549,8 +549,12 @@ static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
549 /* make sure the blinkM is balanced (read/writes) */ 549 /* make sure the blinkM is balanced (read/writes) */
550 while (count > 0) { 550 while (count > 0) {
551 ret = blinkm_write(client, BLM_GET_ADDR, NULL); 551 ret = blinkm_write(client, BLM_GET_ADDR, NULL);
552 if (ret)
553 return ret;
552 usleep_range(5000, 10000); 554 usleep_range(5000, 10000);
553 ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); 555 ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
556 if (ret)
557 return ret;
554 usleep_range(5000, 10000); 558 usleep_range(5000, 10000);
555 if (tmpargs[0] == 0x09) 559 if (tmpargs[0] == 0x09)
556 count = 0; 560 count = 0;
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
new file mode 100644
index 000000000000..437173d1712c
--- /dev/null
+++ b/drivers/leds/leds-lm3692x.c
@@ -0,0 +1,393 @@
1/*
2 * TI lm3692x LED Driver
3 *
4 * Copyright (C) 2017 Texas Instruments
5 *
6 * Author: Dan Murphy <dmurphy@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * Data sheet is located
13 * http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
14 */
15
16#include <linux/gpio/consumer.h>
17#include <linux/i2c.h>
18#include <linux/init.h>
19#include <linux/leds.h>
20#include <linux/module.h>
21#include <linux/mutex.h>
22#include <linux/of.h>
23#include <linux/of_gpio.h>
24#include <linux/regmap.h>
25#include <linux/regulator/consumer.h>
26#include <linux/slab.h>
27#include <uapi/linux/uleds.h>
28
29#define LM3692X_REV 0x0
30#define LM3692X_RESET 0x1
31#define LM3692X_EN 0x10
32#define LM3692X_BRT_CTRL 0x11
33#define LM3692X_PWM_CTRL 0x12
34#define LM3692X_BOOST_CTRL 0x13
35#define LM3692X_AUTO_FREQ_HI 0x15
36#define LM3692X_AUTO_FREQ_LO 0x16
37#define LM3692X_BL_ADJ_THRESH 0x17
38#define LM3692X_BRT_LSB 0x18
39#define LM3692X_BRT_MSB 0x19
40#define LM3692X_FAULT_CTRL 0x1e
41#define LM3692X_FAULT_FLAGS 0x1f
42
43#define LM3692X_SW_RESET BIT(0)
44#define LM3692X_DEVICE_EN BIT(0)
45#define LM3692X_LED1_EN BIT(1)
46#define LM3692X_LED2_EN BIT(2)
47
48/* Brightness Control Bits */
49#define LM3692X_BL_ADJ_POL BIT(0)
50#define LM3692X_RAMP_RATE_125us 0x00
51#define LM3692X_RAMP_RATE_250us BIT(1)
52#define LM3692X_RAMP_RATE_500us BIT(2)
53#define LM3692X_RAMP_RATE_1ms (BIT(1) | BIT(2))
54#define LM3692X_RAMP_RATE_2ms BIT(3)
55#define LM3692X_RAMP_RATE_4ms (BIT(3) | BIT(1))
56#define LM3692X_RAMP_RATE_8ms (BIT(2) | BIT(3))
57#define LM3692X_RAMP_RATE_16ms (BIT(1) | BIT(2) | BIT(3))
58#define LM3692X_RAMP_EN BIT(4)
59#define LM3692X_BRHT_MODE_REG 0x00
60#define LM3692X_BRHT_MODE_PWM BIT(5)
61#define LM3692X_BRHT_MODE_MULTI_RAMP BIT(6)
62#define LM3692X_BRHT_MODE_RAMP_MULTI (BIT(5) | BIT(6))
63#define LM3692X_MAP_MODE_EXP BIT(7)
64
65/* PWM Register Bits */
66#define LM3692X_PWM_FILTER_100 BIT(0)
67#define LM3692X_PWM_FILTER_150 BIT(1)
68#define LM3692X_PWM_FILTER_200 (BIT(0) | BIT(1))
69#define LM3692X_PWM_HYSTER_1LSB BIT(2)
70#define LM3692X_PWM_HYSTER_2LSB BIT(3)
71#define LM3692X_PWM_HYSTER_3LSB (BIT(3) | BIT(2))
72#define LM3692X_PWM_HYSTER_4LSB BIT(4)
73#define LM3692X_PWM_HYSTER_5LSB (BIT(4) | BIT(2))
74#define LM3692X_PWM_HYSTER_6LSB (BIT(4) | BIT(3))
75#define LM3692X_PWM_POLARITY BIT(5)
76#define LM3692X_PWM_SAMP_4MHZ BIT(6)
77#define LM3692X_PWM_SAMP_24MHZ BIT(7)
78
79/* Boost Control Bits */
80#define LM3692X_OCP_PROT_1A BIT(0)
81#define LM3692X_OCP_PROT_1_25A BIT(1)
82#define LM3692X_OCP_PROT_1_5A (BIT(0) | BIT(1))
83#define LM3692X_OVP_21V BIT(2)
84#define LM3692X_OVP_25V BIT(3)
85#define LM3692X_OVP_29V (BIT(2) | BIT(3))
86#define LM3692X_MIN_IND_22UH BIT(4)
87#define LM3692X_BOOST_SW_1MHZ BIT(5)
88#define LM3692X_BOOST_SW_NO_SHIFT BIT(6)
89
90/* Fault Control Bits */
91#define LM3692X_FAULT_CTRL_OVP BIT(0)
92#define LM3692X_FAULT_CTRL_OCP BIT(1)
93#define LM3692X_FAULT_CTRL_TSD BIT(2)
94#define LM3692X_FAULT_CTRL_OPEN BIT(3)
95
96/* Fault Flag Bits */
97#define LM3692X_FAULT_FLAG_OVP BIT(0)
98#define LM3692X_FAULT_FLAG_OCP BIT(1)
99#define LM3692X_FAULT_FLAG_TSD BIT(2)
100#define LM3692X_FAULT_FLAG_SHRT BIT(3)
101#define LM3692X_FAULT_FLAG_OPEN BIT(4)
102
103/**
104 * struct lm3692x_led -
105 * @lock - Lock for reading/writing the device
106 * @client - Pointer to the I2C client
107 * @led_dev - LED class device pointer
108 * @regmap - Devices register map
109 * @enable_gpio - VDDIO/EN gpio to enable communication interface
110 * @regulator - LED supply regulator pointer
111 * @label - LED label
112 */
113struct lm3692x_led {
114 struct mutex lock;
115 struct i2c_client *client;
116 struct led_classdev led_dev;
117 struct regmap *regmap;
118 struct gpio_desc *enable_gpio;
119 struct regulator *regulator;
120 char label[LED_MAX_NAME_SIZE];
121};
122
123static const struct reg_default lm3692x_reg_defs[] = {
124 {LM3692X_EN, 0xf},
125 {LM3692X_BRT_CTRL, 0x61},
126 {LM3692X_PWM_CTRL, 0x73},
127 {LM3692X_BOOST_CTRL, 0x6f},
128 {LM3692X_AUTO_FREQ_HI, 0x0},
129 {LM3692X_AUTO_FREQ_LO, 0x0},
130 {LM3692X_BL_ADJ_THRESH, 0x0},
131 {LM3692X_BRT_LSB, 0x7},
132 {LM3692X_BRT_MSB, 0xff},
133 {LM3692X_FAULT_CTRL, 0x7},
134};
135
136static const struct regmap_config lm3692x_regmap_config = {
137 .reg_bits = 8,
138 .val_bits = 8,
139
140 .max_register = LM3692X_FAULT_FLAGS,
141 .reg_defaults = lm3692x_reg_defs,
142 .num_reg_defaults = ARRAY_SIZE(lm3692x_reg_defs),
143 .cache_type = REGCACHE_RBTREE,
144};
145
146static int lm3692x_fault_check(struct lm3692x_led *led)
147{
148 int ret;
149 unsigned int read_buf;
150
151 ret = regmap_read(led->regmap, LM3692X_FAULT_FLAGS, &read_buf);
152 if (ret)
153 return ret;
154
155 if (read_buf)
156 dev_err(&led->client->dev, "Detected a fault 0x%X\n", read_buf);
157
158 /* The first read may clear the fault. Check again to see if the fault
159 * still exits and return that value.
160 */
161 regmap_read(led->regmap, LM3692X_FAULT_FLAGS, &read_buf);
162 if (read_buf)
163 dev_err(&led->client->dev, "Second read of fault flags 0x%X\n",
164 read_buf);
165
166 return read_buf;
167}
168
169static int lm3692x_brightness_set(struct led_classdev *led_cdev,
170 enum led_brightness brt_val)
171{
172 struct lm3692x_led *led =
173 container_of(led_cdev, struct lm3692x_led, led_dev);
174 int ret;
175 int led_brightness_lsb = (brt_val >> 5);
176
177 mutex_lock(&led->lock);
178
179 ret = lm3692x_fault_check(led);
180 if (ret) {
181 dev_err(&led->client->dev, "Cannot read/clear faults\n");
182 goto out;
183 }
184
185 ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val);
186 if (ret) {
187 dev_err(&led->client->dev, "Cannot write MSB\n");
188 goto out;
189 }
190
191 ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb);
192 if (ret) {
193 dev_err(&led->client->dev, "Cannot write LSB\n");
194 goto out;
195 }
196out:
197 mutex_unlock(&led->lock);
198 return ret;
199}
200
201static int lm3692x_init(struct lm3692x_led *led)
202{
203 int ret;
204
205 if (led->regulator) {
206 ret = regulator_enable(led->regulator);
207 if (ret) {
208 dev_err(&led->client->dev,
209 "Failed to enable regulator\n");
210 return ret;
211 }
212 }
213
214 if (led->enable_gpio)
215 gpiod_direction_output(led->enable_gpio, 1);
216
217 ret = lm3692x_fault_check(led);
218 if (ret) {
219 dev_err(&led->client->dev, "Cannot read/clear faults\n");
220 goto out;
221 }
222
223 ret = regmap_write(led->regmap, LM3692X_BRT_CTRL, 0x00);
224 if (ret)
225 goto out;
226
227 /*
228 * For glitch free operation, the following data should
229 * only be written while device enable bit is 0
230 * per Section 7.5.14 of the data sheet
231 */
232 ret = regmap_write(led->regmap, LM3692X_PWM_CTRL,
233 LM3692X_PWM_FILTER_100 | LM3692X_PWM_SAMP_24MHZ);
234 if (ret)
235 goto out;
236
237 ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL,
238 LM3692X_BRHT_MODE_RAMP_MULTI |
239 LM3692X_BL_ADJ_POL |
240 LM3692X_RAMP_RATE_250us);
241 if (ret)
242 goto out;
243
244 ret = regmap_write(led->regmap, LM3692X_AUTO_FREQ_HI, 0x00);
245 if (ret)
246 goto out;
247
248 ret = regmap_write(led->regmap, LM3692X_AUTO_FREQ_LO, 0x00);
249 if (ret)
250 goto out;
251
252 ret = regmap_write(led->regmap, LM3692X_BL_ADJ_THRESH, 0x00);
253 if (ret)
254 goto out;
255
256 ret = regmap_write(led->regmap, LM3692X_BRT_CTRL,
257 LM3692X_BL_ADJ_POL | LM3692X_PWM_HYSTER_4LSB);
258 if (ret)
259 goto out;
260
261 return ret;
262out:
263 dev_err(&led->client->dev, "Fail writing initialization values\n");
264
265 if (led->enable_gpio)
266 gpiod_direction_output(led->enable_gpio, 0);
267
268 if (led->regulator) {
269 ret = regulator_disable(led->regulator);
270 if (ret)
271 dev_err(&led->client->dev,
272 "Failed to disable regulator\n");
273 }
274
275 return ret;
276}
277
278static int lm3692x_probe(struct i2c_client *client,
279 const struct i2c_device_id *id)
280{
281 int ret;
282 struct lm3692x_led *led;
283 struct device_node *np = client->dev.of_node;
284 struct device_node *child_node;
285 const char *name;
286
287 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
288 if (!led)
289 return -ENOMEM;
290
291 for_each_available_child_of_node(np, child_node) {
292 led->led_dev.default_trigger = of_get_property(child_node,
293 "linux,default-trigger",
294 NULL);
295
296 ret = of_property_read_string(child_node, "label", &name);
297 if (!ret)
298 snprintf(led->label, sizeof(led->label),
299 "%s:%s", id->name, name);
300 else
301 snprintf(led->label, sizeof(led->label),
302 "%s::backlight_cluster", id->name);
303 };
304
305 led->enable_gpio = devm_gpiod_get_optional(&client->dev,
306 "enable", GPIOD_OUT_LOW);
307 if (IS_ERR(led->enable_gpio)) {
308 ret = PTR_ERR(led->enable_gpio);
309 dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret);
310 return ret;
311 }
312
313 led->regulator = devm_regulator_get(&client->dev, "vled");
314 if (IS_ERR(led->regulator))
315 led->regulator = NULL;
316
317 led->client = client;
318 led->led_dev.name = led->label;
319 led->led_dev.brightness_set_blocking = lm3692x_brightness_set;
320
321 mutex_init(&led->lock);
322
323 i2c_set_clientdata(client, led);
324
325 led->regmap = devm_regmap_init_i2c(client, &lm3692x_regmap_config);
326 if (IS_ERR(led->regmap)) {
327 ret = PTR_ERR(led->regmap);
328 dev_err(&client->dev, "Failed to allocate register map: %d\n",
329 ret);
330 return ret;
331 }
332
333 ret = lm3692x_init(led);
334 if (ret)
335 return ret;
336
337 ret = devm_led_classdev_register(&client->dev, &led->led_dev);
338 if (ret) {
339 dev_err(&client->dev, "led register err: %d\n", ret);
340 return ret;
341 }
342
343 return 0;
344}
345
346static int lm3692x_remove(struct i2c_client *client)
347{
348 struct lm3692x_led *led = i2c_get_clientdata(client);
349 int ret;
350
351 if (led->enable_gpio)
352 gpiod_direction_output(led->enable_gpio, 0);
353
354 if (led->regulator) {
355 ret = regulator_disable(led->regulator);
356 if (ret)
357 dev_err(&led->client->dev,
358 "Failed to disable regulator\n");
359 }
360
361 mutex_destroy(&led->lock);
362
363 return 0;
364}
365
366static const struct i2c_device_id lm3692x_id[] = {
367 { "lm36922", 0 },
368 { "lm36923", 1 },
369 { }
370};
371MODULE_DEVICE_TABLE(i2c, lm3692x_id);
372
373static const struct of_device_id of_lm3692x_leds_match[] = {
374 { .compatible = "ti,lm36922", },
375 { .compatible = "ti,lm36923", },
376 {},
377};
378MODULE_DEVICE_TABLE(of, of_lm3692x_leds_match);
379
380static struct i2c_driver lm3692x_driver = {
381 .driver = {
382 .name = "lm3692x",
383 .of_match_table = of_lm3692x_leds_match,
384 },
385 .probe = lm3692x_probe,
386 .remove = lm3692x_remove,
387 .id_table = lm3692x_id,
388};
389module_i2c_driver(lm3692x_driver);
390
391MODULE_DESCRIPTION("Texas Instruments LM3692X LED driver");
392MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
393MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index 3e70775a2d54..39c72a908f3b 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -22,6 +22,7 @@
22#include <linux/of_gpio.h> 22#include <linux/of_gpio.h>
23#include <linux/gpio/consumer.h> 23#include <linux/gpio/consumer.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <uapi/linux/uleds.h>
25 26
26#define LP8860_DISP_CL1_BRT_MSB 0x00 27#define LP8860_DISP_CL1_BRT_MSB 0x00
27#define LP8860_DISP_CL1_BRT_LSB 0x01 28#define LP8860_DISP_CL1_BRT_LSB 0x01
@@ -86,8 +87,6 @@
86 87
87#define LP8860_CLEAR_FAULTS 0x01 88#define LP8860_CLEAR_FAULTS 0x01
88 89
89#define LP8860_DISP_LED_NAME "display_cluster"
90
91/** 90/**
92 * struct lp8860_led - 91 * struct lp8860_led -
93 * @lock - Lock for reading/writing the device 92 * @lock - Lock for reading/writing the device
@@ -98,7 +97,7 @@
98 * @enable_gpio - VDDIO/EN gpio to enable communication interface 97 * @enable_gpio - VDDIO/EN gpio to enable communication interface
99 * @regulator - LED supply regulator pointer 98 * @regulator - LED supply regulator pointer
100 * @label - LED label 99 * @label - LED label
101**/ 100 */
102struct lp8860_led { 101struct lp8860_led {
103 struct mutex lock; 102 struct mutex lock;
104 struct i2c_client *client; 103 struct i2c_client *client;
@@ -107,7 +106,7 @@ struct lp8860_led {
107 struct regmap *eeprom_regmap; 106 struct regmap *eeprom_regmap;
108 struct gpio_desc *enable_gpio; 107 struct gpio_desc *enable_gpio;
109 struct regulator *regulator; 108 struct regulator *regulator;
110 const char *label; 109 char label[LED_MAX_NAME_SIZE];
111}; 110};
112 111
113struct lp8860_eeprom_reg { 112struct lp8860_eeprom_reg {
@@ -247,6 +246,15 @@ static int lp8860_init(struct lp8860_led *led)
247 unsigned int read_buf; 246 unsigned int read_buf;
248 int ret, i, reg_count; 247 int ret, i, reg_count;
249 248
249 if (led->regulator) {
250 ret = regulator_enable(led->regulator);
251 if (ret) {
252 dev_err(&led->client->dev,
253 "Failed to enable regulator\n");
254 return ret;
255 }
256 }
257
250 if (led->enable_gpio) 258 if (led->enable_gpio)
251 gpiod_direction_output(led->enable_gpio, 1); 259 gpiod_direction_output(led->enable_gpio, 1);
252 260
@@ -282,12 +290,25 @@ static int lp8860_init(struct lp8860_led *led)
282 ret = regmap_write(led->regmap, 290 ret = regmap_write(led->regmap,
283 LP8860_EEPROM_CNTRL, 291 LP8860_EEPROM_CNTRL,
284 LP8860_PROGRAM_EEPROM); 292 LP8860_PROGRAM_EEPROM);
285 if (ret) 293 if (ret) {
286 dev_err(&led->client->dev, "Failed programming EEPROM\n"); 294 dev_err(&led->client->dev, "Failed programming EEPROM\n");
295 goto out;
296 }
297
298 return ret;
299
287out: 300out:
288 if (ret) 301 if (ret)
289 if (led->enable_gpio) 302 if (led->enable_gpio)
290 gpiod_direction_output(led->enable_gpio, 0); 303 gpiod_direction_output(led->enable_gpio, 0);
304
305 if (led->regulator) {
306 ret = regulator_disable(led->regulator);
307 if (ret)
308 dev_err(&led->client->dev,
309 "Failed to disable regulator\n");
310 }
311
291 return ret; 312 return ret;
292} 313}
293 314
@@ -365,19 +386,25 @@ static int lp8860_probe(struct i2c_client *client,
365 int ret; 386 int ret;
366 struct lp8860_led *led; 387 struct lp8860_led *led;
367 struct device_node *np = client->dev.of_node; 388 struct device_node *np = client->dev.of_node;
389 struct device_node *child_node;
390 const char *name;
368 391
369 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); 392 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
370 if (!led) 393 if (!led)
371 return -ENOMEM; 394 return -ENOMEM;
372 395
373 led->label = LP8860_DISP_LED_NAME; 396 for_each_available_child_of_node(np, child_node) {
374 397 led->led_dev.default_trigger = of_get_property(child_node,
375 if (client->dev.of_node) { 398 "linux,default-trigger",
376 ret = of_property_read_string(np, "label", &led->label); 399 NULL);
377 if (ret) { 400
378 dev_err(&client->dev, "Missing label in dt\n"); 401 ret = of_property_read_string(child_node, "label", &name);
379 return -EINVAL; 402 if (!ret)
380 } 403 snprintf(led->label, sizeof(led->label), "%s:%s",
404 id->name, name);
405 else
406 snprintf(led->label, sizeof(led->label),
407 "%s::display_cluster", id->name);
381 } 408 }
382 409
383 led->enable_gpio = devm_gpiod_get_optional(&client->dev, 410 led->enable_gpio = devm_gpiod_get_optional(&client->dev,
@@ -394,7 +421,6 @@ static int lp8860_probe(struct i2c_client *client,
394 421
395 led->client = client; 422 led->client = client;
396 led->led_dev.name = led->label; 423 led->led_dev.name = led->label;
397 led->led_dev.max_brightness = LED_FULL;
398 led->led_dev.brightness_set_blocking = lp8860_brightness_set; 424 led->led_dev.brightness_set_blocking = lp8860_brightness_set;
399 425
400 mutex_init(&led->lock); 426 mutex_init(&led->lock);
@@ -421,7 +447,7 @@ static int lp8860_probe(struct i2c_client *client,
421 if (ret) 447 if (ret)
422 return ret; 448 return ret;
423 449
424 ret = led_classdev_register(&client->dev, &led->led_dev); 450 ret = devm_led_classdev_register(&client->dev, &led->led_dev);
425 if (ret) { 451 if (ret) {
426 dev_err(&client->dev, "led register err: %d\n", ret); 452 dev_err(&client->dev, "led register err: %d\n", ret);
427 return ret; 453 return ret;
@@ -435,8 +461,6 @@ static int lp8860_remove(struct i2c_client *client)
435 struct lp8860_led *led = i2c_get_clientdata(client); 461 struct lp8860_led *led = i2c_get_clientdata(client);
436 int ret; 462 int ret;
437 463
438 led_classdev_unregister(&led->led_dev);
439
440 if (led->enable_gpio) 464 if (led->enable_gpio)
441 gpiod_direction_output(led->enable_gpio, 0); 465 gpiod_direction_output(led->enable_gpio, 0);
442 466
@@ -447,6 +471,8 @@ static int lp8860_remove(struct i2c_client *client)
447 "Failed to disable regulator\n"); 471 "Failed to disable regulator\n");
448 } 472 }
449 473
474 mutex_destroy(&led->lock);
475
450 return 0; 476 return 0;
451} 477}
452 478
@@ -456,18 +482,16 @@ static const struct i2c_device_id lp8860_id[] = {
456}; 482};
457MODULE_DEVICE_TABLE(i2c, lp8860_id); 483MODULE_DEVICE_TABLE(i2c, lp8860_id);
458 484
459#ifdef CONFIG_OF
460static const struct of_device_id of_lp8860_leds_match[] = { 485static const struct of_device_id of_lp8860_leds_match[] = {
461 { .compatible = "ti,lp8860", }, 486 { .compatible = "ti,lp8860", },
462 {}, 487 {},
463}; 488};
464MODULE_DEVICE_TABLE(of, of_lp8860_leds_match); 489MODULE_DEVICE_TABLE(of, of_lp8860_leds_match);
465#endif
466 490
467static struct i2c_driver lp8860_driver = { 491static struct i2c_driver lp8860_driver = {
468 .driver = { 492 .driver = {
469 .name = "lp8860", 493 .name = "lp8860",
470 .of_match_table = of_match_ptr(of_lp8860_leds_match), 494 .of_match_table = of_lp8860_leds_match,
471 }, 495 },
472 .probe = lp8860_probe, 496 .probe = lp8860_probe,
473 .remove = lp8860_remove, 497 .remove = lp8860_remove,
@@ -477,4 +501,4 @@ module_i2c_driver(lp8860_driver);
477 501
478MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver"); 502MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver");
479MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 503MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
480MODULE_LICENSE("GPL"); 504MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 8d456dc6c5bf..df80c89ebe7f 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -16,7 +16,6 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/of_platform.h> 18#include <linux/of_platform.h>
19#include <linux/fb.h>
20#include <linux/leds.h> 19#include <linux/leds.h>
21#include <linux/err.h> 20#include <linux/err.h>
22#include <linux/pwm.h> 21#include <linux/pwm.h>
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index bb090216b4dc..a2559b4fdfff 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -81,7 +81,7 @@ config LEDS_TRIGGER_ACTIVITY
81 tristate "LED activity Trigger" 81 tristate "LED activity Trigger"
82 depends on LEDS_TRIGGERS 82 depends on LEDS_TRIGGERS
83 help 83 help
84 This allows LEDs to be controlled by a immediate CPU usage. 84 This allows LEDs to be controlled by an immediate CPU usage.
85 The flash frequency and duty cycle varies from faint flashes to 85 The flash frequency and duty cycle varies from faint flashes to
86 intense brightness depending on the instant CPU load. 86 intense brightness depending on the instant CPU load.
87 If unsure, say N. 87 If unsure, say N.
@@ -135,4 +135,11 @@ config LEDS_TRIGGER_PANIC
135 a different trigger. 135 a different trigger.
136 If unsure, say Y. 136 If unsure, say Y.
137 137
138config LEDS_TRIGGER_NETDEV
139 tristate "LED Netdev Trigger"
140 depends on NET && LEDS_TRIGGERS
141 help
142 This allows LEDs to be controlled by network device activity.
143 If unsure, say Y.
144
138endif # LEDS_TRIGGERS 145endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
index 4a8b6cff7761..f3cfe1950538 100644
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
12obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o 12obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
13obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o 13obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
14obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o 14obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
15obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
new file mode 100644
index 000000000000..6df4781a6308
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -0,0 +1,496 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright 2017 Ben Whitten <ben.whitten@gmail.com>
3// Copyright 2007 Oliver Jowett <oliver@opencloud.com>
4//
5// LED Kernel Netdev Trigger
6//
7// Toggles the LED to reflect the link and traffic state of a named net device
8//
9// Derived from ledtrig-timer.c which is:
10// Copyright 2005-2006 Openedhand Ltd.
11// Author: Richard Purdie <rpurdie@openedhand.com>
12
13#include <linux/atomic.h>
14#include <linux/ctype.h>
15#include <linux/device.h>
16#include <linux/init.h>
17#include <linux/jiffies.h>
18#include <linux/kernel.h>
19#include <linux/leds.h>
20#include <linux/list.h>
21#include <linux/module.h>
22#include <linux/netdevice.h>
23#include <linux/spinlock.h>
24#include <linux/timer.h>
25#include "../leds.h"
26
27/*
28 * Configurable sysfs attributes:
29 *
30 * device_name - network device name to monitor
31 * interval - duration of LED blink, in milliseconds
32 * link - LED's normal state reflects whether the link is up
33 * (has carrier) or not
34 * tx - LED blinks on transmitted data
35 * rx - LED blinks on receive data
36 *
37 */
38
39struct led_netdev_data {
40 spinlock_t lock;
41
42 struct delayed_work work;
43 struct notifier_block notifier;
44
45 struct led_classdev *led_cdev;
46 struct net_device *net_dev;
47
48 char device_name[IFNAMSIZ];
49 atomic_t interval;
50 unsigned int last_activity;
51
52 unsigned long mode;
53#define NETDEV_LED_LINK 0
54#define NETDEV_LED_TX 1
55#define NETDEV_LED_RX 2
56#define NETDEV_LED_MODE_LINKUP 3
57};
58
59enum netdev_led_attr {
60 NETDEV_ATTR_LINK,
61 NETDEV_ATTR_TX,
62 NETDEV_ATTR_RX
63};
64
65static void set_baseline_state(struct led_netdev_data *trigger_data)
66{
67 int current_brightness;
68 struct led_classdev *led_cdev = trigger_data->led_cdev;
69
70 current_brightness = led_cdev->brightness;
71 if (current_brightness)
72 led_cdev->blink_brightness = current_brightness;
73 if (!led_cdev->blink_brightness)
74 led_cdev->blink_brightness = led_cdev->max_brightness;
75
76 if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
77 led_set_brightness(led_cdev, LED_OFF);
78 else {
79 if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
80 led_set_brightness(led_cdev,
81 led_cdev->blink_brightness);
82 else
83 led_set_brightness(led_cdev, LED_OFF);
84
85 /* If we are looking for RX/TX start periodically
86 * checking stats
87 */
88 if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
89 test_bit(NETDEV_LED_RX, &trigger_data->mode))
90 schedule_delayed_work(&trigger_data->work, 0);
91 }
92}
93
94static ssize_t device_name_show(struct device *dev,
95 struct device_attribute *attr, char *buf)
96{
97 struct led_classdev *led_cdev = dev_get_drvdata(dev);
98 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
99 ssize_t len;
100
101 spin_lock_bh(&trigger_data->lock);
102 len = sprintf(buf, "%s\n", trigger_data->device_name);
103 spin_unlock_bh(&trigger_data->lock);
104
105 return len;
106}
107
108static ssize_t device_name_store(struct device *dev,
109 struct device_attribute *attr, const char *buf,
110 size_t size)
111{
112 struct led_classdev *led_cdev = dev_get_drvdata(dev);
113 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
114
115 if (size >= IFNAMSIZ)
116 return -EINVAL;
117
118 cancel_delayed_work_sync(&trigger_data->work);
119
120 spin_lock_bh(&trigger_data->lock);
121
122 if (trigger_data->net_dev) {
123 dev_put(trigger_data->net_dev);
124 trigger_data->net_dev = NULL;
125 }
126
127 strncpy(trigger_data->device_name, buf, size);
128 if (size > 0 && trigger_data->device_name[size - 1] == '\n')
129 trigger_data->device_name[size - 1] = 0;
130
131 if (trigger_data->device_name[0] != 0)
132 trigger_data->net_dev =
133 dev_get_by_name(&init_net, trigger_data->device_name);
134
135 clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
136 if (trigger_data->net_dev != NULL)
137 if (netif_carrier_ok(trigger_data->net_dev))
138 set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
139
140 trigger_data->last_activity = 0;
141
142 set_baseline_state(trigger_data);
143 spin_unlock_bh(&trigger_data->lock);
144
145 return size;
146}
147
148static DEVICE_ATTR_RW(device_name);
149
150static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
151 enum netdev_led_attr attr)
152{
153 struct led_classdev *led_cdev = dev_get_drvdata(dev);
154 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
155 int bit;
156
157 switch (attr) {
158 case NETDEV_ATTR_LINK:
159 bit = NETDEV_LED_LINK;
160 break;
161 case NETDEV_ATTR_TX:
162 bit = NETDEV_LED_TX;
163 break;
164 case NETDEV_ATTR_RX:
165 bit = NETDEV_LED_RX;
166 break;
167 default:
168 return -EINVAL;
169 }
170
171 return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
172}
173
174static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
175 size_t size, enum netdev_led_attr attr)
176{
177 struct led_classdev *led_cdev = dev_get_drvdata(dev);
178 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
179 unsigned long state;
180 int ret;
181 int bit;
182
183 ret = kstrtoul(buf, 0, &state);
184 if (ret)
185 return ret;
186
187 switch (attr) {
188 case NETDEV_ATTR_LINK:
189 bit = NETDEV_LED_LINK;
190 break;
191 case NETDEV_ATTR_TX:
192 bit = NETDEV_LED_TX;
193 break;
194 case NETDEV_ATTR_RX:
195 bit = NETDEV_LED_RX;
196 break;
197 default:
198 return -EINVAL;
199 }
200
201 cancel_delayed_work_sync(&trigger_data->work);
202
203 if (state)
204 set_bit(bit, &trigger_data->mode);
205 else
206 clear_bit(bit, &trigger_data->mode);
207
208 set_baseline_state(trigger_data);
209
210 return size;
211}
212
213static ssize_t link_show(struct device *dev,
214 struct device_attribute *attr, char *buf)
215{
216 return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
217}
218
219static ssize_t link_store(struct device *dev,
220 struct device_attribute *attr, const char *buf, size_t size)
221{
222 return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
223}
224
225static DEVICE_ATTR_RW(link);
226
227static ssize_t tx_show(struct device *dev,
228 struct device_attribute *attr, char *buf)
229{
230 return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
231}
232
233static ssize_t tx_store(struct device *dev,
234 struct device_attribute *attr, const char *buf, size_t size)
235{
236 return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
237}
238
239static DEVICE_ATTR_RW(tx);
240
241static ssize_t rx_show(struct device *dev,
242 struct device_attribute *attr, char *buf)
243{
244 return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
245}
246
247static ssize_t rx_store(struct device *dev,
248 struct device_attribute *attr, const char *buf, size_t size)
249{
250 return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
251}
252
253static DEVICE_ATTR_RW(rx);
254
255static ssize_t interval_show(struct device *dev,
256 struct device_attribute *attr, char *buf)
257{
258 struct led_classdev *led_cdev = dev_get_drvdata(dev);
259 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
260
261 return sprintf(buf, "%u\n",
262 jiffies_to_msecs(atomic_read(&trigger_data->interval)));
263}
264
265static ssize_t interval_store(struct device *dev,
266 struct device_attribute *attr, const char *buf,
267 size_t size)
268{
269 struct led_classdev *led_cdev = dev_get_drvdata(dev);
270 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
271 unsigned long value;
272 int ret;
273
274 ret = kstrtoul(buf, 0, &value);
275 if (ret)
276 return ret;
277
278 /* impose some basic bounds on the timer interval */
279 if (value >= 5 && value <= 10000) {
280 cancel_delayed_work_sync(&trigger_data->work);
281
282 atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
283 set_baseline_state(trigger_data); /* resets timer */
284 }
285
286 return size;
287}
288
289static DEVICE_ATTR_RW(interval);
290
291static int netdev_trig_notify(struct notifier_block *nb,
292 unsigned long evt, void *dv)
293{
294 struct net_device *dev =
295 netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
296 struct led_netdev_data *trigger_data = container_of(nb,
297 struct
298 led_netdev_data,
299 notifier);
300
301 if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
302 && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
303 && evt != NETDEV_CHANGENAME)
304 return NOTIFY_DONE;
305
306 if (strcmp(dev->name, trigger_data->device_name))
307 return NOTIFY_DONE;
308
309 cancel_delayed_work_sync(&trigger_data->work);
310
311 spin_lock_bh(&trigger_data->lock);
312
313 clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
314 switch (evt) {
315 case NETDEV_REGISTER:
316 if (trigger_data->net_dev)
317 dev_put(trigger_data->net_dev);
318 dev_hold(dev);
319 trigger_data->net_dev = dev;
320 break;
321 case NETDEV_CHANGENAME:
322 case NETDEV_UNREGISTER:
323 if (trigger_data->net_dev) {
324 dev_put(trigger_data->net_dev);
325 trigger_data->net_dev = NULL;
326 }
327 break;
328 case NETDEV_UP:
329 case NETDEV_CHANGE:
330 if (netif_carrier_ok(dev))
331 set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
332 break;
333 }
334
335 set_baseline_state(trigger_data);
336
337 spin_unlock_bh(&trigger_data->lock);
338
339 return NOTIFY_DONE;
340}
341
342/* here's the real work! */
343static void netdev_trig_work(struct work_struct *work)
344{
345 struct led_netdev_data *trigger_data = container_of(work,
346 struct
347 led_netdev_data,
348 work.work);
349 struct rtnl_link_stats64 *dev_stats;
350 unsigned int new_activity;
351 struct rtnl_link_stats64 temp;
352 unsigned long interval;
353 int invert;
354
355 /* If we dont have a device, insure we are off */
356 if (!trigger_data->net_dev) {
357 led_set_brightness(trigger_data->led_cdev, LED_OFF);
358 return;
359 }
360
361 /* If we are not looking for RX/TX then return */
362 if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
363 !test_bit(NETDEV_LED_RX, &trigger_data->mode))
364 return;
365
366 dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
367 new_activity =
368 (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
369 dev_stats->tx_packets : 0) +
370 (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
371 dev_stats->rx_packets : 0);
372
373 if (trigger_data->last_activity != new_activity) {
374 led_stop_software_blink(trigger_data->led_cdev);
375
376 invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
377 interval = jiffies_to_msecs(
378 atomic_read(&trigger_data->interval));
379 /* base state is ON (link present) */
380 led_blink_set_oneshot(trigger_data->led_cdev,
381 &interval,
382 &interval,
383 invert);
384 trigger_data->last_activity = new_activity;
385 }
386
387 schedule_delayed_work(&trigger_data->work,
388 (atomic_read(&trigger_data->interval)*2));
389}
390
391static void netdev_trig_activate(struct led_classdev *led_cdev)
392{
393 struct led_netdev_data *trigger_data;
394 int rc;
395
396 trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
397 if (!trigger_data)
398 return;
399
400 spin_lock_init(&trigger_data->lock);
401
402 trigger_data->notifier.notifier_call = netdev_trig_notify;
403 trigger_data->notifier.priority = 10;
404
405 INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
406
407 trigger_data->led_cdev = led_cdev;
408 trigger_data->net_dev = NULL;
409 trigger_data->device_name[0] = 0;
410
411 trigger_data->mode = 0;
412 atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
413 trigger_data->last_activity = 0;
414
415 led_cdev->trigger_data = trigger_data;
416
417 rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
418 if (rc)
419 goto err_out;
420 rc = device_create_file(led_cdev->dev, &dev_attr_link);
421 if (rc)
422 goto err_out_device_name;
423 rc = device_create_file(led_cdev->dev, &dev_attr_rx);
424 if (rc)
425 goto err_out_link;
426 rc = device_create_file(led_cdev->dev, &dev_attr_tx);
427 if (rc)
428 goto err_out_rx;
429 rc = device_create_file(led_cdev->dev, &dev_attr_interval);
430 if (rc)
431 goto err_out_tx;
432 rc = register_netdevice_notifier(&trigger_data->notifier);
433 if (rc)
434 goto err_out_interval;
435 return;
436
437err_out_interval:
438 device_remove_file(led_cdev->dev, &dev_attr_interval);
439err_out_tx:
440 device_remove_file(led_cdev->dev, &dev_attr_tx);
441err_out_rx:
442 device_remove_file(led_cdev->dev, &dev_attr_rx);
443err_out_link:
444 device_remove_file(led_cdev->dev, &dev_attr_link);
445err_out_device_name:
446 device_remove_file(led_cdev->dev, &dev_attr_device_name);
447err_out:
448 led_cdev->trigger_data = NULL;
449 kfree(trigger_data);
450}
451
452static void netdev_trig_deactivate(struct led_classdev *led_cdev)
453{
454 struct led_netdev_data *trigger_data = led_cdev->trigger_data;
455
456 if (trigger_data) {
457 unregister_netdevice_notifier(&trigger_data->notifier);
458
459 device_remove_file(led_cdev->dev, &dev_attr_device_name);
460 device_remove_file(led_cdev->dev, &dev_attr_link);
461 device_remove_file(led_cdev->dev, &dev_attr_rx);
462 device_remove_file(led_cdev->dev, &dev_attr_tx);
463 device_remove_file(led_cdev->dev, &dev_attr_interval);
464
465 cancel_delayed_work_sync(&trigger_data->work);
466
467 if (trigger_data->net_dev)
468 dev_put(trigger_data->net_dev);
469
470 kfree(trigger_data);
471 }
472}
473
474static struct led_trigger netdev_led_trigger = {
475 .name = "netdev",
476 .activate = netdev_trig_activate,
477 .deactivate = netdev_trig_deactivate,
478};
479
480static int __init netdev_trig_init(void)
481{
482 return led_trigger_register(&netdev_led_trigger);
483}
484
485static void __exit netdev_trig_exit(void)
486{
487 led_trigger_unregister(&netdev_led_trigger);
488}
489
490module_init(netdev_trig_init);
491module_exit(netdev_trig_exit);
492
493MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
494MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
495MODULE_DESCRIPTION("Netdev LED trigger");
496MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c
index 7acce64b692a..9d1769073562 100644
--- a/drivers/leds/trigger/ledtrig-transient.c
+++ b/drivers/leds/trigger/ledtrig-transient.c
@@ -1,22 +1,15 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * LED Kernel Transient Trigger 2//
3 * 3// LED Kernel Transient Trigger
4 * Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com> 4//
5 * 5// Transient trigger allows one shot timer activation. Please refer to
6 * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's 6// Documentation/leds/ledtrig-transient.txt for details
7 * ledtrig-heartbeat.c 7// Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com>
8 * Design and use-case input from Jonas Bonn <jonas@southpole.se> and 8//
9 * Neil Brown <neilb@suse.de> 9// Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's
10 * 10// ledtrig-heartbeat.c
11 * This program is free software; you can redistribute it and/or modify 11// Design and use-case input from Jonas Bonn <jonas@southpole.se> and
12 * it under the terms of the GNU General Public License version 2 as 12// Neil Brown <neilb@suse.de>
13 * published by the Free Software Foundation.
14 *
15 */
16/*
17 * Transient trigger allows one shot timer activation. Please refer to
18 * Documentation/leds/ledtrig-transient.txt for details
19*/
20 13
21#include <linux/module.h> 14#include <linux/module.h>
22#include <linux/kernel.h> 15#include <linux/kernel.h>
@@ -238,4 +231,4 @@ module_exit(transient_trig_exit);
238 231
239MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>"); 232MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
240MODULE_DESCRIPTION("Transient LED trigger"); 233MODULE_DESCRIPTION("Transient LED trigger");
241MODULE_LICENSE("GPL"); 234MODULE_LICENSE("GPL v2");