summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-led3
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-oneshot36
-rw-r--r--Documentation/devicetree/bindings/leds/common.txt7
-rw-r--r--Documentation/devicetree/bindings/leds/leds-bcm6328.txt2
-rw-r--r--Documentation/devicetree/bindings/leds/leds-bcm6358.txt2
-rw-r--r--Documentation/devicetree/bindings/leds/leds-gpio.txt9
-rw-r--r--Documentation/devicetree/bindings/leds/leds-is31fl319x.txt59
-rw-r--r--Documentation/devicetree/bindings/leds/leds-pm8058.txt67
-rw-r--r--Documentation/devicetree/bindings/leds/register-bit-led.txt9
-rw-r--r--Documentation/leds/leds-mlxcpld.txt110
-rw-r--r--Documentation/leds/ledtrig-oneshot.txt20
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/leds/Kconfig28
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-triggers.c25
-rw-r--r--drivers/leds/leds-gpio.c78
-rw-r--r--drivers/leds/leds-is31fl319x.c450
-rw-r--r--drivers/leds/leds-mlxcpld.c430
-rw-r--r--drivers/leds/leds-pm8058.c191
-rw-r--r--include/linux/leds.h9
20 files changed, 1446 insertions, 99 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led
index 3646ec85d513..86ace287d48b 100644
--- a/Documentation/ABI/testing/sysfs-class-led
+++ b/Documentation/ABI/testing/sysfs-class-led
@@ -24,7 +24,8 @@ Description:
of led events.
You can change triggers in a similar manner to the way an IO
scheduler is chosen. Trigger specific parameters can appear in
- /sys/class/leds/<led> once a given trigger is selected.
+ /sys/class/leds/<led> once a given trigger is selected. For
+ their documentation see sysfs-class-led-trigger-*.
What: /sys/class/leds/<led>/inverted
Date: January 2011
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-oneshot b/Documentation/ABI/testing/sysfs-class-led-trigger-oneshot
new file mode 100644
index 000000000000..378a3a4df3c8
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-oneshot
@@ -0,0 +1,36 @@
+What: /sys/class/leds/<led>/delay_on
+Date: Jun 2012
+KernelVersion: 3.6
+Contact: linux-leds@vger.kernel.org
+Description:
+ Specifies for how many milliseconds the LED has to stay at
+ LED_FULL brightness after it has been armed.
+ Defaults to 100 ms.
+
+What: /sys/class/leds/<led>/delay_off
+Date: Jun 2012
+KernelVersion: 3.6
+Contact: linux-leds@vger.kernel.org
+Description:
+ Specifies for how many milliseconds the LED has to stay at
+ LED_OFF brightness after it has been armed.
+ Defaults to 100 ms.
+
+What: /sys/class/leds/<led>/invert
+Date: Jun 2012
+KernelVersion: 3.6
+Contact: linux-leds@vger.kernel.org
+Description:
+ Reverse the blink logic. If set to 0 (default) blink on for
+ delay_on ms, then blink off for delay_off ms, leaving the LED
+ normally off. If set to 1, blink off for delay_off ms, then
+ blink on for delay_on ms, leaving the LED normally on.
+ Setting this value also immediately changes the LED state.
+
+What: /sys/class/leds/<led>/shot
+Date: Jun 2012
+KernelVersion: 3.6
+Contact: linux-leds@vger.kernel.org
+Description:
+ Write any non-empty string to signal an events, this starts a
+ blink sequence if not already running.
diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
index 93ef6e6e43b5..696be5792625 100644
--- a/Documentation/devicetree/bindings/leds/common.txt
+++ b/Documentation/devicetree/bindings/leds/common.txt
@@ -19,6 +19,13 @@ Optional properties for child nodes:
a device, i.e. no other LED class device can be assigned the same
label.
+- default-state : The initial state of the LED. Valid values are "on", "off",
+ and "keep". If the LED is already on or off and the default-state property is
+ set the to same value, then no glitch should be produced where the LED
+ momentarily turns off (or on). The "keep" setting will keep the LED at
+ whatever its current state is, without producing a glitch. The default is
+ off if this property is not present.
+
- linux,default-trigger : This parameter, if present, is a
string defining the trigger assigned to the LED. Current triggers are:
"backlight" - LED will act as a back-light, controlled by the framebuffer
diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6328.txt b/Documentation/devicetree/bindings/leds/leds-bcm6328.txt
index 3f48c1eaf085..ccebce597f37 100644
--- a/Documentation/devicetree/bindings/leds/leds-bcm6328.txt
+++ b/Documentation/devicetree/bindings/leds/leds-bcm6328.txt
@@ -49,7 +49,7 @@ LED sub-node optional properties:
- active-low : Boolean, makes LED active low.
Default : false
- default-state : see
- Documentation/devicetree/bindings/leds/leds-gpio.txt
+ Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : see
Documentation/devicetree/bindings/leds/common.txt
diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt
index b22a55bcc65d..da5708e7b43b 100644
--- a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt
+++ b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt
@@ -28,7 +28,7 @@ LED sub-node optional properties:
- active-low : Boolean, makes LED active low.
Default : false
- default-state : see
- Documentation/devicetree/bindings/leds/leds-gpio.txt
+ Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : see
Documentation/devicetree/bindings/leds/common.txt
diff --git a/Documentation/devicetree/bindings/leds/leds-gpio.txt b/Documentation/devicetree/bindings/leds/leds-gpio.txt
index 5b1b43a64265..76535ca37120 100644
--- a/Documentation/devicetree/bindings/leds/leds-gpio.txt
+++ b/Documentation/devicetree/bindings/leds/leds-gpio.txt
@@ -14,13 +14,8 @@ LED sub-node properties:
see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
-- default-state: (optional) The initial state of the LED. Valid
- values are "on", "off", and "keep". If the LED is already on or off
- and the default-state property is set the to same value, then no
- glitch should be produced where the LED momentarily turns off (or
- on). The "keep" setting will keep the LED at whatever its current
- state is, without producing a glitch. The default is off if this
- property is not present.
+- default-state: (optional) The initial state of the LED.
+ see Documentation/devicetree/bindings/leds/common.txt
- retain-state-suspended: (optional) The suspend state can be retained.Such
as charge-led gpio.
- panic-indicator : (optional)
diff --git a/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt b/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt
new file mode 100644
index 000000000000..fc2603484544
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt
@@ -0,0 +1,59 @@
+LEDs connected to is31fl319x LED controller chip
+
+Required properties:
+- compatible : Should be any of
+ "issi,is31fl3190"
+ "issi,is31fl3191"
+ "issi,is31fl3193"
+ "issi,is31fl3196"
+ "issi,is31fl3199"
+ "si-en,sn3199".
+- #address-cells: Must be 1.
+- #size-cells: Must be 0.
+- reg: 0x64, 0x65, 0x66, or 0x67.
+
+Optional properties:
+- audio-gain-db : audio gain selection for external analog modulation input.
+ Valid values: 0 - 21, step by 3 (rounded down)
+ Default: 0
+
+Each led is represented as a sub-node of the issi,is31fl319x device.
+There can be less leds subnodes than the chip can support but not more.
+
+Required led sub-node properties:
+- reg : number of LED line
+ Valid values: 1 - number of leds supported by the chip variant.
+
+Optional led sub-node properties:
+- label : see Documentation/devicetree/bindings/leds/common.txt.
+- linux,default-trigger :
+ see Documentation/devicetree/bindings/leds/common.txt.
+- led-max-microamp : (optional)
+ Valid values: 5000 - 40000, step by 5000 (rounded down)
+ Default: 20000 (20 mA)
+ Note: a driver will take the lowest of all led limits since the
+ chip has a single global setting. The lowest value will be chosen
+ due to the PWM specificity, where lower brightness is achieved
+ by reducing the dury-cycle of pulses and not the current, which
+ will always have its peak value equal to led-max-microamp.
+
+Examples:
+
+fancy_leds: leds@65 {
+ compatible = "issi,is31fl3196";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x65>;
+
+ red_aux: led@1 {
+ label = "red:aux";
+ reg = <1>;
+ led-max-microamp = <10000>;
+ };
+
+ green_power: led@5 {
+ label = "green:power";
+ reg = <5>;
+ linux,default-trigger = "default-on";
+ };
+};
diff --git a/Documentation/devicetree/bindings/leds/leds-pm8058.txt b/Documentation/devicetree/bindings/leds/leds-pm8058.txt
new file mode 100644
index 000000000000..89584c49aab2
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-pm8058.txt
@@ -0,0 +1,67 @@
+Qualcomm PM8058 LED driver
+
+The Qualcomm PM8058 is a multi-functional device which contains
+an LED driver block for up to six LEDs: three normal LEDs, two
+"flash" LEDs and one "keypad backlight" LED. The names are
+quoted because sometimes these LED drivers are used for wildly
+different things than flash or keypad backlight: their names
+are more of a suggestion than a hard-wired usecase.
+
+Hardware-wise the different LEDs support slightly different
+output currents. The "flash" LEDs do not need to charge nor
+do they support external triggers. They are just powerful LED
+drivers.
+
+The LEDs appear as children to the PM8058 device, with the
+proper compatible string. For the PM8058 bindings see:
+mfd/qcom-pm8xxx.txt.
+
+Each LED is represented as a sub-node of the syscon device. Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+
+Required properties:
+- compatible: one of
+ "qcom,pm8058-led" (for the normal LEDs at 0x131, 0x132 and 0x133)
+ "qcom,pm8058-keypad-led" (for the "keypad" LED at 0x48)
+ "qcom,pm8058-flash-led" (for the "flash" LEDs at 0x49 and 0xFB)
+
+Optional properties:
+- label: see Documentation/devicetree/bindings/leds/common.txt
+- default-state: see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
+
+Example:
+
+qcom,ssbi@500000 {
+ pmicintc: pmic@0 {
+ compatible = "qcom,pm8058";
+ led@48 {
+ compatible = "qcom,pm8058-keypad-led";
+ reg = <0x48>;
+ label = "pm8050:white:keypad";
+ default-state = "off";
+ };
+ led@131 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x131>;
+ label = "pm8058:red";
+ default-state = "off";
+ };
+ led@132 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x132>;
+ label = "pm8058:yellow";
+ default-state = "off";
+ linux,default-trigger = "mmc0";
+ };
+ led@133 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x133>;
+ label = "pm8058:green";
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/leds/register-bit-led.txt b/Documentation/devicetree/bindings/leds/register-bit-led.txt
index 379cefdc0bda..59b56365f648 100644
--- a/Documentation/devicetree/bindings/leds/register-bit-led.txt
+++ b/Documentation/devicetree/bindings/leds/register-bit-led.txt
@@ -23,13 +23,8 @@ Optional properties:
see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
-- default-state: (optional) The initial state of the LED. Valid
- values are "on", "off", and "keep". If the LED is already on or off
- and the default-state property is set the to same value, then no
- glitch should be produced where the LED momentarily turns off (or
- on). The "keep" setting will keep the LED at whatever its current
- state is, without producing a glitch. The default is off if this
- property is not present.
+- default-state: (optional) The initial state of the LED
+ see Documentation/devicetree/bindings/leds/common.txt
Example:
diff --git a/Documentation/leds/leds-mlxcpld.txt b/Documentation/leds/leds-mlxcpld.txt
new file mode 100644
index 000000000000..a0e8fd457117
--- /dev/null
+++ b/Documentation/leds/leds-mlxcpld.txt
@@ -0,0 +1,110 @@
+Kernel driver for Mellanox systems LEDs
+=======================================
+
+Provide system LED support for the nex Mellanox systems:
+"msx6710", "msx6720", "msb7700", "msn2700", "msx1410",
+"msn2410", "msb7800", "msn2740", "msn2100".
+
+Description
+-----------
+Driver provides the following LEDs for the systems "msx6710", "msx6720",
+"msb7700", "msn2700", "msx1410", "msn2410", "msb7800", "msn2740":
+ mlxcpld:fan1:green
+ mlxcpld:fan1:red
+ mlxcpld:fan2:green
+ mlxcpld:fan2:red
+ mlxcpld:fan3:green
+ mlxcpld:fan3:red
+ mlxcpld:fan4:green
+ mlxcpld:fan4:red
+ mlxcpld:psu:green
+ mlxcpld:psu:red
+ mlxcpld:status:green
+ mlxcpld:status:red
+
+ "status"
+ CPLD reg offset: 0x20
+ Bits [3:0]
+
+ "psu"
+ CPLD reg offset: 0x20
+ Bits [7:4]
+
+ "fan1"
+ CPLD reg offset: 0x21
+ Bits [3:0]
+
+ "fan2"
+ CPLD reg offset: 0x21
+ Bits [7:4]
+
+ "fan3"
+ CPLD reg offset: 0x22
+ Bits [3:0]
+
+ "fan4"
+ CPLD reg offset: 0x22
+ Bits [7:4]
+
+ Color mask for all the above LEDs:
+ [bit3,bit2,bit1,bit0] or
+ [bit7,bit6,bit5,bit4]:
+ [0,0,0,0] = LED OFF
+ [0,1,0,1] = Red static ON
+ [1,1,0,1] = Green static ON
+ [0,1,1,0] = Red blink 3Hz
+ [1,1,1,0] = Green blink 3Hz
+ [0,1,1,1] = Red blink 6Hz
+ [1,1,1,1] = Green blink 6Hz
+
+Driver provides the following LEDs for the system "msn2100":
+ mlxcpld:fan:green
+ mlxcpld:fan:red
+ mlxcpld:psu1:green
+ mlxcpld:psu1:red
+ mlxcpld:psu2:green
+ mlxcpld:psu2:red
+ mlxcpld:status:green
+ mlxcpld:status:red
+ mlxcpld:uid:blue
+
+ "status"
+ CPLD reg offset: 0x20
+ Bits [3:0]
+
+ "fan"
+ CPLD reg offset: 0x21
+ Bits [3:0]
+
+ "psu1"
+ CPLD reg offset: 0x23
+ Bits [3:0]
+
+ "psu2"
+ CPLD reg offset: 0x23
+ Bits [7:4]
+
+ "uid"
+ CPLD reg offset: 0x24
+ Bits [3:0]
+
+ Color mask for all the above LEDs, excepted uid:
+ [bit3,bit2,bit1,bit0] or
+ [bit7,bit6,bit5,bit4]:
+ [0,0,0,0] = LED OFF
+ [0,1,0,1] = Red static ON
+ [1,1,0,1] = Green static ON
+ [0,1,1,0] = Red blink 3Hz
+ [1,1,1,0] = Green blink 3Hz
+ [0,1,1,1] = Red blink 6Hz
+ [1,1,1,1] = Green blink 6Hz
+
+ Color mask for uid LED:
+ [bit3,bit2,bit1,bit0]:
+ [0,0,0,0] = LED OFF
+ [1,1,0,1] = Blue static ON
+ [1,1,1,0] = Blue blink 3Hz
+ [1,1,1,1] = Blue blink 6Hz
+
+Driver supports HW blinking at 3Hz and 6Hz frequency (50% duty cycle).
+For 3Hz duty cylce is about 167 msec, for 6Hz is about 83 msec.
diff --git a/Documentation/leds/ledtrig-oneshot.txt b/Documentation/leds/ledtrig-oneshot.txt
index 07cd1fa41a3a..fe57474a12e2 100644
--- a/Documentation/leds/ledtrig-oneshot.txt
+++ b/Documentation/leds/ledtrig-oneshot.txt
@@ -21,24 +21,8 @@ below:
echo oneshot > trigger
-This adds the following sysfs attributes to the LED:
-
- delay_on - specifies for how many milliseconds the LED has to stay at
- LED_FULL brightness after it has been armed.
- Default to 100 ms.
-
- delay_off - specifies for how many milliseconds the LED has to stay at
- LED_OFF brightness after it has been armed.
- Default to 100 ms.
-
- invert - reverse the blink logic. If set to 0 (default) blink on for delay_on
- ms, then blink off for delay_off ms, leaving the LED normally off. If
- set to 1, blink off for delay_off ms, then blink on for delay_on ms,
- leaving the LED normally on.
- Setting this value also immediately change the LED state.
-
- shot - write any non-empty string to signal an events, this starts a blink
- sequence if not already running.
+This adds sysfs attributes to the LED that are documented in:
+Documentation/ABI/testing/sysfs-class-led-trigger-oneshot
Example use-case: network devices, initialization:
diff --git a/MAINTAINERS b/MAINTAINERS
index d33c0383575b..ac8f3cec03f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7678,6 +7678,13 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxsw/
+MELLANOX MLXCPLD LED DRIVER
+M: Vadim Pasternak <vadimp@mellanox.com>
+L: linux-leds@vger.kernel.org
+S: Supported
+F: drivers/leds/leds-mlxcpld.c
+F: Documentation/leds/leds-mlxcpld.txt
+
MELLANOX PLATFORM DRIVER
M: Vadim Pasternak <vadimp@mellanox.com>
L: platform-driver-x86@vger.kernel.org
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9dcc9b13d495..7a628c6516f6 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -584,6 +584,18 @@ config LEDS_SEAD3
This driver can also be built as a module. If so the module
will be called leds-sead3.
+config LEDS_IS31FL319X
+ tristate "LED Support for ISSI IS31FL319x I2C LED controller family"
+ depends on LEDS_CLASS && I2C && OF
+ select REGMAP_I2C
+ help
+ This option enables support for LEDs connected to ISSI IS31FL319x
+ fancy LED driver chips accessed via the I2C bus.
+ Driver supports individual PWM brightness control for each channel.
+
+ This driver can also be built as a module. If so the module will be
+ called leds-is31fl319x.
+
config LEDS_IS31FL32XX
tristate "LED support for ISSI IS31FL32XX I2C LED controller family"
depends on LEDS_CLASS && I2C && OF
@@ -631,6 +643,22 @@ config LEDS_VERSATILE
This option enabled support for the LEDs on the ARM Versatile
and RealView boards. Say Y to enabled these.
+config LEDS_PM8058
+ tristate "LED Support for the Qualcomm PM8058 PMIC"
+ depends on MFD_PM8921_CORE
+ depends on LEDS_CLASS
+ help
+ Choose this option if you want to use the LED drivers in
+ the Qualcomm PM8058 PMIC.
+
+config LEDS_MLXCPLD
+ tristate "LED support for the Mellanox boards"
+ depends on X86_64 && DMI
+ depends on LEDS_CLASS
+ help
+ This option enabled support for the LEDs on the Mellanox
+ boards. Say Y to enabled these.
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 0684c865a1c0..3965070190f5 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -67,7 +67,10 @@ obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o
+obj-$(CONFIG_LEDS_IS31FL319X) += leds-is31fl319x.o
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
+obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
+obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index c92702a684ce..431123b048a2 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -11,7 +11,7 @@
*
*/
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -81,21 +81,23 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
down_read(&led_cdev->trigger_lock);
if (!led_cdev->trigger)
- len += sprintf(buf+len, "[none] ");
+ len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
else
- len += sprintf(buf+len, "none ");
+ len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
list_for_each_entry(trig, &trigger_list, next_trig) {
if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
trig->name))
- len += sprintf(buf+len, "[%s] ", trig->name);
+ len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
+ trig->name);
else
- len += sprintf(buf+len, "%s ", trig->name);
+ len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
+ trig->name);
}
up_read(&led_cdev->trigger_lock);
up_read(&triggers_list_lock);
- len += sprintf(len+buf, "\n");
+ len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
return len;
}
EXPORT_SYMBOL_GPL(led_trigger_show);
@@ -108,6 +110,9 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
char *envp[2];
const char *name;
+ if (!led_cdev->trigger && !trig)
+ return;
+
name = trig ? trig->name : "none";
event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
@@ -136,7 +141,9 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
if (event) {
envp[0] = event;
envp[1] = NULL;
- kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp);
+ if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
+ dev_err(led_cdev->dev,
+ "%s: Error sending uevent\n", __func__);
kfree(event);
}
}
@@ -357,7 +364,3 @@ void led_trigger_unregister_simple(struct led_trigger *trig)
kfree(trig);
}
EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
-
-MODULE_AUTHOR("Richard Purdie");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("LED Triggers Core");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 9b991d46ed84..d400dcaf4d29 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -26,15 +26,19 @@ struct gpio_led_data {
struct gpio_desc *gpiod;
u8 can_sleep;
u8 blinking;
- int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
- unsigned long *delay_on, unsigned long *delay_off);
+ gpio_blink_set_t platform_gpio_blink_set;
};
+static inline struct gpio_led_data *
+ cdev_to_gpio_led_data(struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct gpio_led_data, cdev);
+}
+
static void gpio_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- struct gpio_led_data *led_dat =
- container_of(led_cdev, struct gpio_led_data, cdev);
+ struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev);
int level;
if (value == LED_OFF)
@@ -64,8 +68,7 @@ static int gpio_led_set_blocking(struct led_classdev *led_cdev,
static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
- struct gpio_led_data *led_dat =
- container_of(led_cdev, struct gpio_led_data, cdev);
+ struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev);
led_dat->blinking = 1;
return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
@@ -74,8 +77,7 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- int (*blink_set)(struct gpio_desc *, int, unsigned long *,
- unsigned long *))
+ gpio_blink_set_t blink_set)
{
int ret, state;
@@ -120,10 +122,13 @@ static int create_gpio_led(const struct gpio_led *template,
led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
- if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpiod_get_value_cansleep(led_dat->gpiod);
- else
+ if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) {
+ state = gpiod_get_value_cansleep(led_dat->gpiod);
+ if (state < 0)
+ return state;
+ } else {
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+ }
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
@@ -134,7 +139,7 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;
- return led_classdev_register(parent, &led_dat->cdev);
+ return devm_led_classdev_register(parent, &led_dat->cdev);
}
struct gpio_leds_priv {
@@ -154,7 +159,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;
- struct device_node *np;
count = device_get_child_node_count(dev);
if (!count)
@@ -168,26 +172,22 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
struct gpio_led led = {};
const char *state = NULL;
+ struct device_node *np = to_of_node(child);
led.gpiod = devm_get_gpiod_from_child(dev, NULL, child);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
- ret = PTR_ERR(led.gpiod);
- goto err;
+ return ERR_CAST(led.gpiod);
}
- np = to_of_node(child);
-
- if (fwnode_property_present(child, "label")) {
- fwnode_property_read_string(child, "label", &led.name);
- } else {
- if (IS_ENABLED(CONFIG_OF) && !led.name && np)
- led.name = np->name;
- if (!led.name) {
- ret = -EINVAL;
- goto err;
- }
+ ret = fwnode_property_read_string(child, "label", &led.name);
+ if (ret && IS_ENABLED(CONFIG_OF) && np)
+ led.name = np->name;
+ if (!led.name) {
+ fwnode_handle_put(child);
+ return ERR_PTR(-EINVAL);
}
+
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
@@ -209,18 +209,13 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
ret = create_gpio_led(&led, led_dat, dev, NULL);
if (ret < 0) {
fwnode_handle_put(child);
- goto err;
+ return ERR_PTR(ret);
}
led_dat->cdev.dev->of_node = np;
priv->num_leds++;
}
return priv;
-
-err:
- for (count = priv->num_leds - 1; count >= 0; count--)
- led_classdev_unregister(&priv->leds[count].cdev);
- return ERR_PTR(ret);
}
static const struct of_device_id of_gpio_leds_match[] = {
@@ -248,13 +243,8 @@ static int gpio_led_probe(struct platform_device *pdev)
ret = create_gpio_led(&pdata->leds[i],
&priv->leds[i],
&pdev->dev, pdata->gpio_blink_set);
- if (ret < 0) {
- /* On failure: unwind the led creations */
- for (i = i - 1; i >= 0; i--)
- led_classdev_unregister(
- &priv->leds[i].cdev);
+ if (ret < 0)
return ret;
- }
}
} else {
priv = gpio_leds_create(pdev);
@@ -267,17 +257,6 @@ static int gpio_led_probe(struct platform_device *pdev)
return 0;
}
-static int gpio_led_remove(struct platform_device *pdev)
-{
- struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < priv->num_leds; i++)
- led_classdev_unregister(&priv->leds[i].cdev);
-
- return 0;
-}
-
static void gpio_led_shutdown(struct platform_device *pdev)
{
struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
@@ -292,7 +271,6 @@ static void gpio_led_shutdown(struct platform_device *pdev)
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
- .remove = gpio_led_remove,
.shutdown = gpio_led_shutdown,
.driver = {
.name = "leds-gpio",
diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c
new file mode 100644
index 000000000000..f123309597e4
--- /dev/null
+++ b/drivers/leds/leds-is31fl319x.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2015-16 Golden Delicious Computers
+ *
+ * Author: Nikolaus Schaller <hns@goldelico.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * LED driver for the IS31FL319{0,1,3,6,9} to drive 1, 3, 6 or 9 light
+ * effect LEDs.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* register numbers */
+#define IS31FL319X_SHUTDOWN 0x00
+#define IS31FL319X_CTRL1 0x01
+#define IS31FL319X_CTRL2 0x02
+#define IS31FL319X_CONFIG1 0x03
+#define IS31FL319X_CONFIG2 0x04
+#define IS31FL319X_RAMP_MODE 0x05
+#define IS31FL319X_BREATH_MASK 0x06
+#define IS31FL319X_PWM(channel) (0x07 + channel)
+#define IS31FL319X_DATA_UPDATE 0x10
+#define IS31FL319X_T0(channel) (0x11 + channel)
+#define IS31FL319X_T123_1 0x1a
+#define IS31FL319X_T123_2 0x1b
+#define IS31FL319X_T123_3 0x1c
+#define IS31FL319X_T4(channel) (0x1d + channel)
+#define IS31FL319X_TIME_UPDATE 0x26
+#define IS31FL319X_RESET 0xff
+
+#define IS31FL319X_REG_CNT (IS31FL319X_RESET + 1)
+
+#define IS31FL319X_MAX_LEDS 9
+
+/* CS (Current Setting) in CONFIG2 register */
+#define IS31FL319X_CONFIG2_CS_SHIFT 4
+#define IS31FL319X_CONFIG2_CS_MASK 0x7
+#define IS31FL319X_CONFIG2_CS_STEP_REF 12
+
+#define IS31FL319X_CURRENT_MIN ((u32)5000)
+#define IS31FL319X_CURRENT_MAX ((u32)40000)
+#define IS31FL319X_CURRENT_STEP ((u32)5000)
+#define IS31FL319X_CURRENT_DEFAULT ((u32)20000)
+
+/* Audio gain in CONFIG2 register */
+#define IS31FL319X_AUDIO_GAIN_DB_MAX ((u32)21)
+#define IS31FL319X_AUDIO_GAIN_DB_STEP ((u32)3)
+
+/*
+ * regmap is used as a cache of chip's register space,
+ * to avoid reading back brightness values from chip,
+ * which is known to hang.
+ */
+struct is31fl319x_chip {
+ const struct is31fl319x_chipdef *cdef;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct mutex lock;
+ u32 audio_gain_db;
+
+ struct is31fl319x_led {
+ struct is31fl319x_chip *chip;
+ struct led_classdev cdev;
+ u32 max_microamp;
+ bool configured;
+ } leds[IS31FL319X_MAX_LEDS];
+};
+
+struct is31fl319x_chipdef {
+ int num_leds;
+};
+
+static const struct is31fl319x_chipdef is31fl3190_cdef = {
+ .num_leds = 1,
+};
+
+static const struct is31fl319x_chipdef is31fl3193_cdef = {
+ .num_leds = 3,
+};
+
+static const struct is31fl319x_chipdef is31fl3196_cdef = {
+ .num_leds = 6,
+};
+
+static const struct is31fl319x_chipdef is31fl3199_cdef = {
+ .num_leds = 9,
+};
+
+static const struct of_device_id of_is31fl319x_match[] = {
+ { .compatible = "issi,is31fl3190", .data = &is31fl3190_cdef, },
+ { .compatible = "issi,is31fl3191", .data = &is31fl3190_cdef, },
+ { .compatible = "issi,is31fl3193", .data = &is31fl3193_cdef, },
+ { .compatible = "issi,is31fl3196", .data = &is31fl3196_cdef, },
+ { .compatible = "issi,is31fl3199", .data = &is31fl3199_cdef, },
+ { .compatible = "si-en,sn3199", .data = &is31fl3199_cdef, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, of_is31fl319x_match);
+
+static int is31fl319x_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct is31fl319x_led *led = container_of(cdev, struct is31fl319x_led,
+ cdev);
+ struct is31fl319x_chip *is31 = led->chip;
+ int chan = led - is31->leds;
+ int ret;
+ int i;
+ u8 ctrl1 = 0, ctrl2 = 0;
+
+ dev_dbg(&is31->client->dev, "%s %d: %d\n", __func__, chan, brightness);
+
+ mutex_lock(&is31->lock);
+
+ /* update PWM register */
+ ret = regmap_write(is31->regmap, IS31FL319X_PWM(chan), brightness);
+ if (ret < 0)
+ goto out;
+
+ /* read current brightness of all PWM channels */
+ for (i = 0; i < is31->cdef->num_leds; i++) {
+ unsigned int pwm_value;
+ bool on;
+
+ /*
+ * since neither cdev nor the chip can provide
+ * the current setting, we read from the regmap cache
+ */
+
+ ret = regmap_read(is31->regmap, IS31FL319X_PWM(i), &pwm_