History

Merge tag 'leds_for_4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds

Pull LED updates from Jacek Anaszewski: "New drivers: - add LED support for MT6323 PMIC - add LED support for Motorola CPCAP PMIC New features and improvements: - add LED trigger for all CPUs aggregated which is useful on tiny boards with more CPU cores than LED pins - add OF variants of LED registering functions as a preparation for adding generic support for Device Tree parsing - dell-led improvements and cleanups, followed by moving it to the x86 platform driver subsystem which is a more appropriate place for it - extend pca9532 Device Tree support by adding the LEDs 'default-state' property - extend pca963x Device Tree support by adding nxp,inverted-out property for inverting the polarity of the output - remove ACPI support for lp3952 since it relied on a non-official ACPI IDs" * tag 'leds_for_4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: leds: pca9532: Extend pca9532 device tree support leds: cpcap: new driver mfd: cpcap: Add missing include dependencies leds: lp3952: Use 'if (ret)' pattern leds: lp3952: Remove ACPI support for lp3952 leds: mt6323: Fix an off by one bug in probe dt-bindings: leds: Add document bindings for leds-mt6323 leds: Add LED support for MT6323 PMIC leds: gpio: use OF variant of LED registering function leds: core: add OF variants of LED registering functions platform/x86: dell-wmi-led: fix coding style issues dell-led: move driver to drivers/platform/x86/dell-wmi-led.c dell-led: remove code related to mic mute LED platform/x86: dell-laptop: import dell_micmute_led_set() from drivers/leds/dell-led.c ALSA: hda - rename dell_led_set_func to dell_micmute_led_set_func ALSA: hda - use dell_micmute_led_set() instead of dell_app_wmi_led_set() dell-led: remove GUID check from dell_micmute_led_set() leds/trigger/cpu: Add LED trigger for all CPUs aggregated

Linus Torvalds committed 9 years ago

Commit 85724ed2 parents 477d7ca 28c5fe921 files · +1043 −178Browse files

Unified · Split

21 files
  1. Documentation/devicetree/bindings/leds/leds-cpcap.txt +29 −0
  2. Documentation/devicetree/bindings/leds/leds-mt6323.txt +60 −0
  3. Documentation/devicetree/bindings/leds/leds-pca9532.txt +10 −0
  4. drivers/leds/Kconfig +17 −10
  5. drivers/leds/Makefile +2 −1
  6. drivers/leds/led-class.c +16 −10
  7. drivers/leds/leds-cpcap.c +239 −0
  8. drivers/leds/leds-gpio.c +6 −6
  9. drivers/leds/leds-lp3952.c +4 −14
  10. drivers/leds/leds-mt6323.c +502 −0
  11. drivers/leds/leds-pca9532.c +26 −1
  12. drivers/leds/trigger/ledtrig-cpu.c +31 −2
  13. drivers/platform/x86/Kconfig +8 −0
  14. drivers/platform/x86/Makefile +1 −0
  15. drivers/platform/x86/dell-laptop.c +28 −0
  16. drivers/platform/x86/dell-wmi-led.c +33 −108
  17. include/linux/dell-led.h +1 −5
  18. include/linux/leds-pca9532.h +2 −2
  19. include/linux/leds.h +10 −4
  20. include/linux/mfd/motorola-cpcap.h +3 −0
  21. sound/pci/hda/dell_wmi_helper.c +15 −15
Documentation/devicetree/bindings/leds/leds-cpcap.txt+29−0
@@ -0,0 +1,29 @@
1+Motorola CPCAP PMIC LEDs
2+------------------------
3+
4+This module is part of the CPCAP. For more details about the whole
5+chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
6+
7+Requires node properties:
8+- compatible: should be one of
9+ * "motorola,cpcap-led-mdl" (Main Display Lighting)
10+ * "motorola,cpcap-led-kl" (Keyboard Lighting)
11+ * "motorola,cpcap-led-adl" (Aux Display Lighting)
12+ * "motorola,cpcap-led-red" (Red Triode)
13+ * "motorola,cpcap-led-green" (Green Triode)
14+ * "motorola,cpcap-led-blue" (Blue Triode)
15+ * "motorola,cpcap-led-cf" (Camera Flash)
16+ * "motorola,cpcap-led-bt" (Bluetooth)
17+ * "motorola,cpcap-led-cp" (Camera Privacy LED)
18+- label: see Documentation/devicetree/bindings/leds/common.txt
19+- vdd-supply: A phandle to the regulator powering the LED
20+
21+Example:
22+
23+&cpcap {
24+ cpcap_led_red: red-led {
25+ compatible = "motorola,cpcap-led-red";
26+ label = "cpcap:red";
27+ vdd-supply = <&sw5>;
28+ };
29+};
Documentation/devicetree/bindings/leds/leds-mt6323.txt+60−0
@@ -0,0 +1,60 @@
1+Device Tree Bindings for LED support on MT6323 PMIC
2+
3+MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED
4+controllers are defined as the subnode of the function node provided by MT6323
5+PMIC controller that is being defined as one kind of Muti-Function Device (MFD)
6+using shared bus called PMIC wrapper for each subfunction to access remote
7+MT6323 PMIC hardware.
8+
9+For MT6323 MFD bindings see:
10+Documentation/devicetree/bindings/mfd/mt6397.txt
11+For MediaTek PMIC wrapper bindings see:
12+Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
13+
14+Required properties:
15+- compatible : Must be "mediatek,mt6323-led"
16+- address-cells : Must be 1
17+- size-cells : Must be 0
18+
19+Each led is represented as a child node of the mediatek,mt6323-led that
20+describes the initial behavior for each LED physically and currently only four
21+LED child nodes can be supported.
22+
23+Required properties for the LED child node:
24+- reg : LED channel number (0..3)
25+
26+Optional properties for the LED child node:
27+- label : See Documentation/devicetree/bindings/leds/common.txt
28+- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt
29+- default-state: See Documentation/devicetree/bindings/leds/common.txt
30+
31+Example:
32+
33+ mt6323: pmic {
34+ compatible = "mediatek,mt6323";
35+
36+ ...
37+
38+ mt6323led: leds {
39+ compatible = "mediatek,mt6323-led";
40+ #address-cells = <1>;
41+ #size-cells = <0>;
42+
43+ led@0 {
44+ reg = <0>;
45+ label = "LED0";
46+ linux,default-trigger = "timer";
47+ default-state = "on";
48+ };
49+ led@1 {
50+ reg = <1>;
51+ label = "LED1";
52+ default-state = "off";
53+ };
54+ led@2 {
55+ reg = <2>;
56+ label = "LED2";
57+ default-state = "on";
58+ };
59+ };
60+ };
Documentation/devicetree/bindings/leds/leds-pca9532.txt+10−0
@@ -17,6 +17,8 @@ Optional sub-node properties: · 16 unmodified lines
1717 - label: see Documentation/devicetree/bindings/leds/common.txt
1818 - type: Output configuration, see dt-bindings/leds/leds-pca9532.h (default NONE)
1919 - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
20+ - default-state: see Documentation/devicetree/bindings/leds/common.txt
21+ This property is only valid for sub-nodes of type <PCA9532_TYPE_LED>.
2022
2123 Example:
2224 #include <dt-bindings/leds/leds-pca9532.h>
@@ -33,6 +35,14 @@ Example: · 10 unmodified lines
3335 label = "pca:green:power";
3436 type = <PCA9532_TYPE_LED>;
3537 };
38+ kernel-booting {
39+ type = <PCA9532_TYPE_LED>;
40+ default-state = "on";
41+ };
42+ sys-stat {
43+ type = <PCA9532_TYPE_LED>;
44+ default-state = "keep"; // don't touch, was set by U-Boot
45+ };
3646 };
3747
3848 For more product information please see the link below:
drivers/leds/Kconfig+17−10
@@ -76,6 +76,15 @@ config LEDS_BCM6358 · 75 unmodified lines
7676 This option enables support for LEDs connected to the BCM6358
7777 LED HW controller accessed via MMIO registers.
7878
79+config LEDS_CPCAP
80+ tristate "LED Support for Motorola CPCAP"
81+ depends on LEDS_CLASS
82+ depends on MFD_CPCAP
83+ depends on OF
84+ help
85+ This option enables support for LEDs offered by Motorola's
86+ CPCAP PMIC.
87+
7988 config LEDS_LM3530
8089 tristate "LCD Backlight driver for LM3530"
8190 depends on LEDS_CLASS
@@ -126,6 +135,14 @@ config LEDS_MIKROTIK_RB532 · 44 unmodified lines
126135 This option enables support for the so called "User LED" of
127136 Mikrotik's Routerboard 532.
128137
138+config LEDS_MT6323
139+ tristate "LED Support for Mediatek MT6323 PMIC"
140+ depends on LEDS_CLASS
141+ depends on MFD_MT6397
142+ help
143+ This option enables support for on-chip LED drivers found on
144+ Mediatek MT6323 PMIC.
145+
129146 config LEDS_S3C24XX
130147 tristate "LED Support for Samsung S3C24XX GPIO LEDs"
131148 depends on LEDS_CLASS
@@ -241,7 +258,6 @@ config LEDS_LP3952 · 109 unmodified lines
241258 tristate "LED Support for TI LP3952 2 channel LED driver"
242259 depends on LEDS_CLASS
243260 depends on I2C
244− depends on ACPI
245261 depends on GPIOLIB
246262 select REGMAP_I2C
247263 help
@@ -463,15 +479,6 @@ config LEDS_ADP5520 · 215 unmodified lines
463479 To compile this driver as a module, choose M here: the module will
464480 be called leds-adp5520.
465481
466−config LEDS_DELL_NETBOOKS
467− tristate "External LED on Dell Business Netbooks"
468− depends on LEDS_CLASS
469− depends on X86 && ACPI_WMI
470− depends on DELL_SMBIOS
471− help
472− This adds support for the Latitude 2100 and similar
473− notebooks that have an external LED.
474−
475482 config LEDS_MC13783
476483 tristate "LED Support for MC13XXX PMIC"
477484 depends on LEDS_CLASS
drivers/leds/Makefile+2−1
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o · 10 unmodified lines
1111 obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
1212 obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
1313 obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
14+obj-$(CONFIG_LEDS_CPCAP) += leds-cpcap.o
1415 obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
1516 obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
1617 obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
@@ -52,7 +53,6 @@ obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o · 35 unmodified lines
5253 obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
5354 obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
5455 obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
55−obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
5656 obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
5757 obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
5858 obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
@@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o · 13 unmodified lines
7272 obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
7373 obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
7474 obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o
75+obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
7576
7677 # LED SPI Drivers
7778 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
drivers/leds/led-class.c+16−10
@@ -244,11 +244,14 @@ static int led_classdev_next_name(const char *init_name, char *name, · 243 unmodified lines
244244 }
245245
246246 /**
247− * led_classdev_register - register a new object of led_classdev class.
248− * @parent: The device to register.
247+ * of_led_classdev_register - register a new object of led_classdev class.
248+ *
249+ * @parent: parent of LED device
249250 * @led_cdev: the led_classdev structure for this device.
251+ * @np: DT node describing this LED
250252 */
251−int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
253+int of_led_classdev_register(struct device *parent, struct device_node *np,
254+ struct led_classdev *led_cdev)
252255 {
253256 char name[LED_MAX_NAME_SIZE];
254257 int ret;
@@ -261,6 +264,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · 6 unmodified lines
261264 led_cdev, led_cdev->groups, "%s", name);
262265 if (IS_ERR(led_cdev->dev))
263266 return PTR_ERR(led_cdev->dev);
267+ led_cdev->dev->of_node = np;
264268
265269 if (ret)
266270 dev_warn(parent, "Led %s renamed to %s due to name collision",
@@ -303,7 +307,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · 36 unmodified lines
303307
304308 return 0;
305309 }
306−EXPORT_SYMBOL_GPL(led_classdev_register);
310+EXPORT_SYMBOL_GPL(of_led_classdev_register);
307311
308312 /**
309313 * led_classdev_unregister - unregisters a object of led_properties class.
@@ -348,12 +352,14 @@ static void devm_led_classdev_release(struct device *dev, void *res) · 38 unmodified lines
348352 }
349353
350354 /**
351− * devm_led_classdev_register - resource managed led_classdev_register()
352− * @parent: The device to register.
355+ * devm_of_led_classdev_register - resource managed led_classdev_register()
356+ *
357+ * @parent: parent of LED device
353358 * @led_cdev: the led_classdev structure for this device.
354359 */
355−int devm_led_classdev_register(struct device *parent,
356− struct led_classdev *led_cdev)
360+int devm_of_led_classdev_register(struct device *parent,
361+ struct device_node *np,
362+ struct led_classdev *led_cdev)
357363 {
358364 struct led_classdev **dr;
359365 int rc;
@@ -362,7 +368,7 @@ int devm_led_classdev_register(struct device *parent, · 2 unmodified lines
362368 if (!dr)
363369 return -ENOMEM;
364370
365− rc = led_classdev_register(parent, led_cdev);
371+ rc = of_led_classdev_register(parent, np, led_cdev);
366372 if (rc) {
367373 devres_free(dr);
368374 return rc;
@@ -373,7 +379,7 @@ int devm_led_classdev_register(struct device *parent, · 4 unmodified lines
373379
374380 return 0;
375381 }
376−EXPORT_SYMBOL_GPL(devm_led_classdev_register);
382+EXPORT_SYMBOL_GPL(devm_of_led_classdev_register);
377383
378384 static int devm_led_classdev_match(struct device *dev, void *res, void *data)
379385 {
drivers/leds/leds-cpcap.c+239−0
@@ -0,0 +1,239 @@
1+/*
2+ * Copyright (c) 2017 Sebastian Reichel <sre@kernel.org>
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License version 2 or
6+ * later as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ */
13+
14+#include <linux/leds.h>
15+#include <linux/mfd/motorola-cpcap.h>
16+#include <linux/module.h>
17+#include <linux/mutex.h>
18+#include <linux/of_device.h>
19+#include <linux/platform_device.h>
20+#include <linux/regmap.h>
21+#include <linux/regulator/consumer.h>
22+
23+#define CPCAP_LED_NO_CURRENT 0x0001
24+
25+struct cpcap_led_info {
26+ u16 reg;
27+ u16 mask;
28+ u16 limit;
29+ u16 init_mask;
30+ u16 init_val;
31+};
32+
33+static const struct cpcap_led_info cpcap_led_red = {
34+ .reg = CPCAP_REG_REDC,
35+ .mask = 0x03FF,
36+ .limit = 31,
37+};
38+
39+static const struct cpcap_led_info cpcap_led_green = {
40+ .reg = CPCAP_REG_GREENC,
41+ .mask = 0x03FF,
42+ .limit = 31,
43+};
44+
45+static const struct cpcap_led_info cpcap_led_blue = {
46+ .reg = CPCAP_REG_BLUEC,
47+ .mask = 0x03FF,
48+ .limit = 31,
49+};
50+
51+/* aux display light */
52+static const struct cpcap_led_info cpcap_led_adl = {
53+ .reg = CPCAP_REG_ADLC,
54+ .mask = 0x000F,
55+ .limit = 1,
56+ .init_mask = 0x7FFF,
57+ .init_val = 0x5FF0,
58+};
59+
60+/* camera privacy led */
61+static const struct cpcap_led_info cpcap_led_cp = {
62+ .reg = CPCAP_REG_CLEDC,
63+ .mask = 0x0007,
64+ .limit = 1,
65+ .init_mask = 0x03FF,
66+ .init_val = 0x0008,
67+};
68+
69+struct cpcap_led {
70+ struct led_classdev led;
71+ const struct cpcap_led_info *info;
72+ struct device *dev;
73+ struct regmap *regmap;
74+ struct mutex update_lock;
75+ struct regulator *vdd;
76+ bool powered;
77+
78+ u32 current_limit;
79+};
80+
81+static u16 cpcap_led_val(u8 current_limit, u8 duty_cycle)
82+{
83+ current_limit &= 0x1f; /* 5 bit */
84+ duty_cycle &= 0x0f; /* 4 bit */
85+
86+ return current_limit << 4 | duty_cycle;
87+}
88+
89+static int cpcap_led_set_power(struct cpcap_led *led, bool status)
90+{
91+ int err;
92+
93+ if (status == led->powered)
94+ return 0;
95+
96+ if (status)
97+ err = regulator_enable(led->vdd);
98+ else
99+ err = regulator_disable(led->vdd);
100+
101+ if (err) {
102+ dev_err(led->dev, "regulator failure: %d", err);
103+ return err;
104+ }
105+
106+ led->powered = status;
107+
108+ return 0;
109+}
110+
111+static int cpcap_led_set(struct led_classdev *ledc, enum led_brightness value)
112+{
113+ struct cpcap_led *led = container_of(ledc, struct cpcap_led, led);
114+ int brightness;
115+ int err;
116+
117+ mutex_lock(&led->update_lock);
118+
119+ if (value > LED_OFF) {
120+ err = cpcap_led_set_power(led, true);
121+ if (err)
122+ goto exit;
123+ }
124+
125+ if (value == LED_OFF) {
126+ /* Avoid HW issue by turning off current before duty cycle */
127+ err = regmap_update_bits(led->regmap,
128+ led->info->reg, led->info->mask, CPCAP_LED_NO_CURRENT);
129+ if (err) {
130+ dev_err(led->dev, "regmap failed: %d", err);
131+ goto exit;
132+ }
133+
134+ brightness = cpcap_led_val(value, LED_OFF);
135+ } else {
136+ brightness = cpcap_led_val(value, LED_ON);
137+ }
138+
139+ err = regmap_update_bits(led->regmap, led->info->reg, led->info->mask,
140+ brightness);
141+ if (err) {
142+ dev_err(led->dev, "regmap failed: %d", err);
143+ goto exit;
144+ }
145+
146+ if (value == LED_OFF) {
147+ err = cpcap_led_set_power(led, false);
148+ if (err)
149+ goto exit;
150+ }
151+
152+exit:
153+ mutex_unlock(&led->update_lock);
154+ return err;
155+}
156+
157+static const struct of_device_id cpcap_led_of_match[] = {
158+ { .compatible = "motorola,cpcap-led-red", .data = &cpcap_led_red },
159+ { .compatible = "motorola,cpcap-led-green", .data = &cpcap_led_green },
160+ { .compatible = "motorola,cpcap-led-blue", .data = &cpcap_led_blue },
161+ { .compatible = "motorola,cpcap-led-adl", .data = &cpcap_led_adl },
162+ { .compatible = "motorola,cpcap-led-cp", .data = &cpcap_led_cp },
163+ {},
164+};
165+MODULE_DEVICE_TABLE(of, cpcap_led_of_match);
166+
167+static int cpcap_led_probe(struct platform_device *pdev)
168+{
169+ const struct of_device_id *match;
170+ struct cpcap_led *led;
171+ int err;
172+
173+ match = of_match_device(of_match_ptr(cpcap_led_of_match), &pdev->dev);
174+ if (!match || !match->data)
175+ return -EINVAL;
176+
177+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
178+ if (!led)
179+ return -ENOMEM;
180+ platform_set_drvdata(pdev, led);
181+ led->info = match->data;
182+ led->dev = &pdev->dev;
183+
184+ if (led->info->reg == 0x0000) {
185+ dev_err(led->dev, "Unsupported LED");
186+ return -ENODEV;
187+ }
188+
189+ led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
190+ if (!led->regmap)
191+ return -ENODEV;
192+
193+ led->vdd = devm_regulator_get(&pdev->dev, "vdd");
194+ if (IS_ERR(led->vdd)) {
195+ err = PTR_ERR(led->vdd);
196+ dev_err(led->dev, "Couldn't get regulator: %d", err);
197+ return err;
198+ }
199+
200+ err = device_property_read_string(&pdev->dev, "label", &led->led.name);
201+ if (err) {
202+ dev_err(led->dev, "Couldn't read LED label: %d", err);
203+ return err;
204+ }
205+
206+ if (led->info->init_mask) {
207+ err = regmap_update_bits(led->regmap, led->info->reg,
208+ led->info->init_mask, led->info->init_val);
209+ if (err) {
210+ dev_err(led->dev, "regmap failed: %d", err);
211+ return err;
212+ }
213+ }
214+
215+ mutex_init(&led->update_lock);
216+
217+ led->led.max_brightness = led->info->limit;
218+ led->led.brightness_set_blocking = cpcap_led_set;
219+ err = devm_led_classdev_register(&pdev->dev, &led->led);
220+ if (err) {
221+ dev_err(led->dev, "Couldn't register LED: %d", err);
222+ return err;
223+ }
224+
225+ return 0;
226+}
227+
228+static struct platform_driver cpcap_led_driver = {
229+ .probe = cpcap_led_probe,
230+ .driver = {
231+ .name = "cpcap-led",
232+ .of_match_table = cpcap_led_of_match,
233+ },
234+};
235+module_platform_driver(cpcap_led_driver);
236+
237+MODULE_DESCRIPTION("CPCAP LED driver");
238+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
239+MODULE_LICENSE("GPL");
drivers/leds/leds-gpio.c+6−6
@@ -77,7 +77,7 @@ static int gpio_blink_set(struct led_classdev *led_cdev, · 76 unmodified lines
7777
7878 static int create_gpio_led(const struct gpio_led *template,
7979 struct gpio_led_data *led_dat, struct device *parent,
80− gpio_blink_set_t blink_set)
80+ struct device_node *np, gpio_blink_set_t blink_set)
8181 {
8282 int ret, state;
8383
@@ -139,7 +139,7 @@ static int create_gpio_led(const struct gpio_led *template, · 55 unmodified lines
139139 if (ret < 0)
140140 return ret;
141141
142− return devm_led_classdev_register(parent, &led_dat->cdev);
142+ return devm_of_led_classdev_register(parent, np, &led_dat->cdev);
143143 }
144144
145145 struct gpio_leds_priv {
@@ -208,7 +208,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) · 62 unmodified lines
208208 if (fwnode_property_present(child, "panic-indicator"))
209209 led.panic_indicator = 1;
210210
211− ret = create_gpio_led(&led, led_dat, dev, NULL);
211+ ret = create_gpio_led(&led, led_dat, dev, np, NULL);
212212 if (ret < 0) {
213213 fwnode_handle_put(child);
214214 return ERR_PTR(ret);
@@ -242,9 +242,9 @@ static int gpio_led_probe(struct platform_device *pdev) · 27 unmodified lines
242242
243243 priv->num_leds = pdata->num_leds;
244244 for (i = 0; i < priv->num_leds; i++) {
245− ret = create_gpio_led(&pdata->leds[i],
246− &priv->leds[i],
247− &pdev->dev, pdata->gpio_blink_set);
245+ ret = create_gpio_led(&pdata->leds[i], &priv->leds[i],
246+ &pdev->dev, NULL,
247+ pdata->gpio_blink_set);
248248 if (ret < 0)
249249 return ret;
250250 }
drivers/leds/leds-lp3952.c+4−14
@@ -10,7 +10,6 @@ · 9 unmodified lines
1010 *
1111 */
1212
13−#include <linux/acpi.h>
1413 #include <linux/delay.h>
1514 #include <linux/gpio.h>
1615 #include <linux/i2c.h>
@@ -103,10 +102,11 @@ static int lp3952_get_label(struct device *dev, const char *label, char *dest) · 86 unmodified lines
103102 const char *str;
104103
105104 ret = device_property_read_string(dev, label, &str);
106− if (!ret)
107− strncpy(dest, str, LP3952_LABEL_MAX_LEN);
105+ if (ret)
106+ return ret;
108107
109− return ret;
108+ strncpy(dest, str, LP3952_LABEL_MAX_LEN);
109+ return 0;
110110 }
111111
112112 static int lp3952_register_led_classdev(struct lp3952_led_array *priv)
@@ -276,19 +276,9 @@ static const struct i2c_device_id lp3952_id[] = { · 163 unmodified lines
276276 };
277277 MODULE_DEVICE_TABLE(i2c, lp3952_id);
278278
279−#ifdef CONFIG_ACPI
280−static const struct acpi_device_id lp3952_acpi_match[] = {
281− {"TXNW3952", 0},
282− {}
283−};
284−
285−MODULE_DEVICE_TABLE(acpi, lp3952_acpi_match);
286−#endif
287−
288279 static struct i2c_driver lp3952_i2c_driver = {
289280 .driver = {
290281 .name = LP3952_NAME,
291− .acpi_match_table = ACPI_PTR(lp3952_acpi_match),
292282 },
293283 .probe = lp3952_probe,
294284 .remove = lp3952_remove,
drivers/leds/leds-mt6323.c+502−0
@@ -0,0 +1,502 @@
1+/*
2+ * LED driver for Mediatek MT6323 PMIC
3+ *
4+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
5+ *
6+ * This program is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU General Public License as
8+ * published by the Free Software Foundation; either version 2 of
9+ * the License, or (at your option) any later version.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ */
16+#include <linux/kernel.h>
17+#include <linux/leds.h>
18+#include <linux/mfd/mt6323/registers.h>
19+#include <linux/mfd/mt6397/core.h>
20+#include <linux/module.h>
21+#include <linux/of.h>
22+#include <linux/platform_device.h>
23+#include <linux/regmap.h>
24+
25+/*
26+ * Register field for MT6323_TOP_CKPDN0 to enable
27+ * 32K clock common for LED device.
28+ */
29+#define MT6323_RG_DRV_32K_CK_PDN BIT(11)
30+#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
31+
32+/*
33+ * Register field for MT6323_TOP_CKPDN2 to enable
34+ * individual clock for LED device.
35+ */
36+#define MT6323_RG_ISINK_CK_PDN(i) BIT(i)
37+#define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i)
38+
39+/*
40+ * Register field for MT6323_TOP_CKCON1 to select
41+ * clock source.
42+ */
43+#define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i))
44+
45+/*
46+ * Register for MT6323_ISINK_CON0 to setup the
47+ * duty cycle of the blink.
48+ */
49+#define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i))
50+#define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8)
51+#define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \
52+ MT6323_ISINK_DIM_DUTY_MASK)
53+
54+/* Register to setup the period of the blink. */
55+#define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i))
56+#define MT6323_ISINK_DIM_FSEL_MASK (0xffff)
57+#define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK)
58+
59+/* Register to control the brightness. */
60+#define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i))
61+#define MT6323_ISINK_CH_STEP_SHIFT 12
62+#define MT6323_ISINK_CH_STEP_MASK (0x7 << 12)
63+#define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \
64+ MT6323_ISINK_CH_STEP_MASK)
65+#define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1)
66+#define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \
67+ MT6323_ISINK_SFSTR0_TC_MASK)
68+#define MT6323_ISINK_SFSTR0_EN_MASK BIT(0)
69+#define MT6323_ISINK_SFSTR0_EN BIT(0)
70+
71+/* Register to LED channel enablement. */
72+#define MT6323_ISINK_CH_EN_MASK(i) BIT(i)
73+#define MT6323_ISINK_CH_EN(i) BIT(i)
74+
75+#define MT6323_MAX_PERIOD 10000
76+#define MT6323_MAX_LEDS 4
77+#define MT6323_MAX_BRIGHTNESS 6
78+#define MT6323_UNIT_DUTY 3125
79+#define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\
80+ (p) * MT6323_UNIT_DUTY)
81+
82+struct mt6323_leds;
83+
84+/**
85+ * struct mt6323_led - state container for the LED device
86+ * @id: the identifier in MT6323 LED device
87+ * @parent: the pointer to MT6323 LED controller
88+ * @cdev: LED class device for this LED device
89+ * @current_brightness: current state of the LED device
90+ */
91+struct mt6323_led {
92+ int id;
93+ struct mt6323_leds *parent;
94+ struct led_classdev cdev;
95+ enum led_brightness current_brightness;
96+};
97+
98+/**
99+ * struct mt6323_leds - state container for holding LED controller
100+ * of the driver
101+ * @dev: the device pointer
102+ * @hw: the underlying hardware providing shared
103+ * bus for the register operations
104+ * @lock: the lock among process context
105+ * @led: the array that contains the state of individual
106+ * LED device
107+ */
108+struct mt6323_leds {
109+ struct device *dev;
110+ struct mt6397_chip *hw;
111+ /* protect among process context */
112+ struct mutex lock;
113+ struct mt6323_led *led[MT6323_MAX_LEDS];
114+};
115+
116+static int mt6323_led_hw_brightness(struct led_classdev *cdev,
117+ enum led_brightness brightness)
118+{
119+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
120+ struct mt6323_leds *leds = led->parent;
121+ struct regmap *regmap = leds->hw->regmap;
122+ u32 con2_mask = 0, con2_val = 0;
123+ int ret;
124+
125+ /*
126+ * Setup current output for the corresponding
127+ * brightness level.
128+ */
129+ con2_mask |= MT6323_ISINK_CH_STEP_MASK |
130+ MT6323_ISINK_SFSTR0_TC_MASK |
131+ MT6323_ISINK_SFSTR0_EN_MASK;
132+ con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) |
133+ MT6323_ISINK_SFSTR0_TC(2) |
134+ MT6323_ISINK_SFSTR0_EN;
135+
136+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
137+ con2_mask, con2_val);
138+ return ret;
139+}
140+
141+static int mt6323_led_hw_off(struct led_classdev *cdev)
142+{
143+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
144+ struct mt6323_leds *leds = led->parent;
145+ struct regmap *regmap = leds->hw->regmap;
146+ unsigned int status;
147+ int ret;
148+
149+ status = MT6323_ISINK_CH_EN(led->id);
150+ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
151+ MT6323_ISINK_CH_EN_MASK(led->id), ~status);
152+ if (ret < 0)
153+ return ret;
154+
155+ usleep_range(100, 300);
156+ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
157+ MT6323_RG_ISINK_CK_PDN_MASK(led->id),
158+ MT6323_RG_ISINK_CK_PDN(led->id));
159+ if (ret < 0)
160+ return ret;
161+
162+ return 0;
163+}
164+
165+static enum led_brightness
166+mt6323_get_led_hw_brightness(struct led_classdev *cdev)
167+{
168+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
169+ struct mt6323_leds *leds = led->parent;
170+ struct regmap *regmap = leds->hw->regmap;
171+ unsigned int status;
172+ int ret;
173+
174+ ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
175+ if (ret < 0)
176+ return ret;
177+
178+ if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
179+ return 0;
180+
181+ ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
182+ if (ret < 0)
183+ return ret;
184+
185+ if (!(status & MT6323_ISINK_CH_EN(led->id)))
186+ return 0;
187+
188+ ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
189+ if (ret < 0)
190+ return ret;
191+
192+ return ((status & MT6323_ISINK_CH_STEP_MASK)
193+ >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
194+}
195+
196+static int mt6323_led_hw_on(struct led_classdev *cdev,
197+ enum led_brightness brightness)
198+{
199+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
200+ struct mt6323_leds *leds = led->parent;
201+ struct regmap *regmap = leds->hw->regmap;
202+ unsigned int status;
203+ int ret;
204+
205+ /*
206+ * Setup required clock source, enable the corresponding
207+ * clock and channel and let work with continuous blink as
208+ * the default.
209+ */
210+ ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
211+ MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
212+ if (ret < 0)
213+ return ret;
214+
215+ status = MT6323_RG_ISINK_CK_PDN(led->id);
216+ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
217+ MT6323_RG_ISINK_CK_PDN_MASK(led->id),
218+ ~status);
219+ if (ret < 0)
220+ return ret;
221+
222+ usleep_range(100, 300);
223+
224+ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
225+ MT6323_ISINK_CH_EN_MASK(led->id),
226+ MT6323_ISINK_CH_EN(led->id));
227+ if (ret < 0)
228+ return ret;
229+
230+ ret = mt6323_led_hw_brightness(cdev, brightness);
231+ if (ret < 0)
232+ return ret;
233+
234+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
235+ MT6323_ISINK_DIM_DUTY_MASK,
236+ MT6323_ISINK_DIM_DUTY(31));
237+ if (ret < 0)
238+ return ret;
239+
240+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
241+ MT6323_ISINK_DIM_FSEL_MASK,
242+ MT6323_ISINK_DIM_FSEL(1000));
243+ if (ret < 0)
244+ return ret;
245+
246+ return 0;
247+}
248+
249+static int mt6323_led_set_blink(struct led_classdev *cdev,
250+ unsigned long *delay_on,
251+ unsigned long *delay_off)
252+{
253+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
254+ struct mt6323_leds *leds = led->parent;
255+ struct regmap *regmap = leds->hw->regmap;
256+ unsigned long period;
257+ u8 duty_hw;
258+ int ret;
259+
260+ /*
261+ * Units are in ms, if over the hardware able
262+ * to support, fallback into software blink
263+ */
264+ period = *delay_on + *delay_off;
265+
266+ if (period > MT6323_MAX_PERIOD)
267+ return -EINVAL;
268+
269+ /*
270+ * LED subsystem requires a default user
271+ * friendly blink pattern for the LED so using
272+ * 1Hz duty cycle 50% here if without specific
273+ * value delay_on and delay off being assigned.
274+ */
275+ if (!*delay_on && !*delay_off) {
276+ *delay_on = 500;
277+ *delay_off = 500;
278+ }
279+
280+ /*
281+ * Calculate duty_hw based on the percentage of period during
282+ * which the led is ON.
283+ */
284+ duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
285+
286+ /* hardware doesn't support zero duty cycle. */
287+ if (!duty_hw)
288+ return -EINVAL;
289+
290+ mutex_lock(&leds->lock);
291+ /*
292+ * Set max_brightness as the software blink behavior
293+ * when no blink brightness.
294+ */
295+ if (!led->current_brightness) {
296+ ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
297+ if (ret < 0)
298+ goto out;
299+ led->current_brightness = cdev->max_brightness;
300+ }
301+
302+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
303+ MT6323_ISINK_DIM_DUTY_MASK,
304+ MT6323_ISINK_DIM_DUTY(duty_hw - 1));
305+ if (ret < 0)
306+ goto out;
307+
308+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
309+ MT6323_ISINK_DIM_FSEL_MASK,
310+ MT6323_ISINK_DIM_FSEL(period - 1));
311+out:
312+ mutex_unlock(&leds->lock);
313+
314+ return ret;
315+}
316+
317+static int mt6323_led_set_brightness(struct led_classdev *cdev,
318+ enum led_brightness brightness)
319+{
320+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
321+ struct mt6323_leds *leds = led->parent;
322+ int ret;
323+
324+ mutex_lock(&leds->lock);
325+
326+ if (!led->current_brightness && brightness) {
327+ ret = mt6323_led_hw_on(cdev, brightness);
328+ if (ret < 0)
329+ goto out;
330+ } else if (brightness) {
331+ ret = mt6323_led_hw_brightness(cdev, brightness);
332+ if (ret < 0)
333+ goto out;
334+ } else {
335+ ret = mt6323_led_hw_off(cdev);
336+ if (ret < 0)
337+ goto out;
338+ }
339+
340+ led->current_brightness = brightness;
341+out:
342+ mutex_unlock(&leds->lock);
343+
344+ return ret;
345+}
346+
347+static int mt6323_led_set_dt_default(struct led_classdev *cdev,
348+ struct device_node *np)
349+{
350+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
351+ const char *state;
352+ int ret = 0;
353+
354+ led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
355+ led->cdev.default_trigger = of_get_property(np,
356+ "linux,default-trigger",
357+ NULL);
358+
359+ state = of_get_property(np, "default-state", NULL);
360+ if (state) {
361+ if (!strcmp(state, "keep")) {
362+ ret = mt6323_get_led_hw_brightness(cdev);
363+ if (ret < 0)
364+ return ret;
365+ led->current_brightness = ret;
366+ ret = 0;
367+ } else if (!strcmp(state, "on")) {
368+ ret =
369+ mt6323_led_set_brightness(cdev, cdev->max_brightness);
370+ } else {
371+ ret = mt6323_led_set_brightness(cdev, LED_OFF);
372+ }
373+ }
374+
375+ return ret;
376+}
377+
378+static int mt6323_led_probe(struct platform_device *pdev)
379+{
380+ struct device *dev = &pdev->dev;
381+ struct device_node *np = pdev->dev.of_node;
382+ struct device_node *child;
383+ struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
384+ struct mt6323_leds *leds;
385+ struct mt6323_led *led;
386+ int ret;
387+ unsigned int status;
388+ u32 reg;
389+
390+ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
391+ if (!leds)
392+ return -ENOMEM;
393+
394+ platform_set_drvdata(pdev, leds);
395+ leds->dev = dev;
396+
397+ /*
398+ * leds->hw points to the underlying bus for the register
399+ * controlled.
400+ */
401+ leds->hw = hw;
402+ mutex_init(&leds->lock);
403+
404+ status = MT6323_RG_DRV_32K_CK_PDN;
405+ ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
406+ MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
407+ if (ret < 0) {
408+ dev_err(leds->dev,
409+ "Failed to update MT6323_TOP_CKPDN0 Register\n");
410+ return ret;
411+ }
412+
413+ for_each_available_child_of_node(np, child) {
414+ ret = of_property_read_u32(child, "reg", &reg);
415+ if (ret) {
416+ dev_err(dev, "Failed to read led 'reg' property\n");
417+ goto put_child_node;
418+ }
419+
420+ if (reg >= MT6323_MAX_LEDS || leds->led[reg]) {
421+ dev_err(dev, "Invalid led reg %u\n", reg);
422+ ret = -EINVAL;
423+ goto put_child_node;
424+ }
425+
426+ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
427+ if (!led) {
428+ ret = -ENOMEM;
429+ goto put_child_node;
430+ }
431+
432+ leds->led[reg] = led;
433+ leds->led[reg]->id = reg;
434+ leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
435+ leds->led[reg]->cdev.brightness_set_blocking =
436+ mt6323_led_set_brightness;
437+ leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
438+ leds->led[reg]->cdev.brightness_get =
439+ mt6323_get_led_hw_brightness;
440+ leds->led[reg]->parent = leds;
441+
442+ ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
443+ if (ret < 0) {
444+ dev_err(leds->dev,
445+ "Failed to LED set default from devicetree\n");
446+ goto put_child_node;
447+ }
448+
449+ ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
450+ if (ret) {
451+ dev_err(&pdev->dev, "Failed to register LED: %d\n",
452+ ret);
453+ goto put_child_node;
454+ }
455+ leds->led[reg]->cdev.dev->of_node = child;
456+ }
457+
458+ return 0;
459+
460+put_child_node:
461+ of_node_put(child);
462+ return ret;
463+}
464+
465+static int mt6323_led_remove(struct platform_device *pdev)
466+{
467+ struct mt6323_leds *leds = platform_get_drvdata(pdev);
468+ int i;
469+
470+ /* Turn the LEDs off on driver removal. */
471+ for (i = 0 ; leds->led[i] ; i++)
472+ mt6323_led_hw_off(&leds->led[i]->cdev);
473+
474+ regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
475+ MT6323_RG_DRV_32K_CK_PDN_MASK,
476+ MT6323_RG_DRV_32K_CK_PDN);
477+
478+ mutex_destroy(&leds->lock);
479+
480+ return 0;
481+}
482+
483+static const struct of_device_id mt6323_led_dt_match[] = {
484+ { .compatible = "mediatek,mt6323-led" },
485+ {},
486+};
487+MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
488+
489+static struct platform_driver mt6323_led_driver = {
490+ .probe = mt6323_led_probe,
491+ .remove = mt6323_led_remove,
492+ .driver = {
493+ .name = "mt6323-led",
494+ .of_match_table = mt6323_led_dt_match,
495+ },
496+};
497+
498+module_platform_driver(mt6323_led_driver);
499+
500+MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
501+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
502+MODULE_LICENSE("GPL");
drivers/leds/leds-pca9532.c+26−1
@@ -254,6 +254,21 @@ static void pca9532_input_work(struct work_struct *work) · 253 unmodified lines
254254 mutex_unlock(&data->update_lock);
255255 }
256256
257+static enum pca9532_state pca9532_getled(struct pca9532_led *led)
258+{
259+ struct i2c_client *client = led->client;
260+ struct pca9532_data *data = i2c_get_clientdata(client);
261+ u8 maxleds = data->chip_info->num_leds;
262+ char reg;
263+ enum pca9532_state ret;
264+
265+ mutex_lock(&data->update_lock);
266+ reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
267+ ret = reg >> LED_NUM(led->id)/2;
268+ mutex_unlock(&data->update_lock);
269+ return ret;
270+}
271+
257272 #ifdef CONFIG_LEDS_PCA9532_GPIO
258273 static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
259274 {
@@ -366,7 +381,10 @@ static int pca9532_configure(struct i2c_client *client, · 106 unmodified lines
366381 gpios++;
367382 break;
368383 case PCA9532_TYPE_LED:
369− led->state = pled->state;
384+ if (pled->state == PCA9532_KEEP)
385+ led->state = pca9532_getled(led);
386+ else
387+ led->state = pled->state;
370388 led->name = pled->name;
371389 led->ldev.name = led->name;
372390 led->ldev.default_trigger = pled->default_trigger;
@@ -456,6 +474,7 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np) · 83 unmodified lines
456474 const struct of_device_id *match;
457475 int devid, maxleds;
458476 int i = 0;
477+ const char *state;
459478
460479 match = of_match_device(of_pca9532_leds_match, dev);
461480 if (!match)
@@ -475,6 +494,12 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np) · 13 unmodified lines
475494 of_property_read_u32(child, "type", &pdata->leds[i].type);
476495 of_property_read_string(child, "linux,default-trigger",
477496 &pdata->leds[i].default_trigger);
497+ if (!of_property_read_string(child, "default-state", &state)) {
498+ if (!strcmp(state, "on"))
499+ pdata->leds[i].state = PCA9532_ON;
500+ else if (!strcmp(state, "keep"))
501+ pdata->leds[i].state = PCA9532_KEEP;
502+ }
478503 if (++i >= maxleds) {
479504 of_node_put(child);
480505 break;
drivers/leds/trigger/ledtrig-cpu.c+31−2
@@ -31,12 +31,16 @@ · 30 unmodified lines
3131 #define MAX_NAME_LEN 8
3232
3333 struct led_trigger_cpu {
34+ bool is_active;
3435 char name[MAX_NAME_LEN];
3536 struct led_trigger *_trig;
3637 };
3738
3839 static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
3940
41+static struct led_trigger *trig_cpu_all;
42+static atomic_t num_active_cpus = ATOMIC_INIT(0);
43+
4044 /**
4145 * ledtrig_cpu - emit a CPU event as a trigger
4246 * @evt: CPU event to be emitted
@@ -47,26 +51,46 @@ static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); · 4 unmodified lines
4751 void ledtrig_cpu(enum cpu_led_event ledevt)
4852 {
4953 struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig);
54+ bool is_active = trig->is_active;
5055
5156 /* Locate the correct CPU LED */
5257 switch (ledevt) {
5358 case CPU_LED_IDLE_END:
5459 case CPU_LED_START:
5560 /* Will turn the LED on, max brightness */
56− led_trigger_event(trig->_trig, LED_FULL);
61+ is_active = true;
5762 break;
5863
5964 case CPU_LED_IDLE_START:
6065 case CPU_LED_STOP:
6166 case CPU_LED_HALTED:
6267 /* Will turn the LED off */
63− led_trigger_event(trig->_trig, LED_OFF);
68+ is_active = false;
6469 break;
6570
6671 default:
6772 /* Will leave the LED as it is */
6873 break;
6974 }
75+
76+ if (is_active != trig->is_active) {
77+ unsigned int active_cpus;
78+ unsigned int total_cpus;
79+
80+ /* Update trigger state */
81+ trig->is_active = is_active;
82+ atomic_add(is_active ? 1 : -1, &num_active_cpus);
83+ active_cpus = atomic_read(&num_active_cpus);
84+ total_cpus = num_present_cpus();
85+
86+ led_trigger_event(trig->_trig,
87+ is_active ? LED_FULL : LED_OFF);
88+
89+
90+ led_trigger_event(trig_cpu_all,
91+ DIV_ROUND_UP(LED_FULL * active_cpus, total_cpus));
92+
93+ }
7094 }
7195 EXPORT_SYMBOL(ledtrig_cpu);
7296
@@ -112,6 +136,11 @@ static int __init ledtrig_cpu_init(void) · 39 unmodified lines
112136 /* Supports up to 9999 cpu cores */
113137 BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
114138
139+ /*
140+ * Registering a trigger for all CPUs.
141+ */
142+ led_trigger_register_simple("cpu", &trig_cpu_all);
143+
115144 /*
116145 * Registering CPU led trigger for each CPU core here
117146 * ignores CPU hotplug, but after this CPU hotplug works
drivers/platform/x86/Kconfig+8−0
@@ -141,6 +141,14 @@ config DELL_WMI_AIO · 140 unmodified lines
141141 To compile this driver as a module, choose M here: the module will
142142 be called dell-wmi-aio.
143143
144+config DELL_WMI_LED
145+ tristate "External LED on Dell Business Netbooks"
146+ depends on LEDS_CLASS
147+ depends on ACPI_WMI
148+ help
149+ This adds support for the Latitude 2100 and similar
150+ notebooks that have an external LED.
151+
144152 config DELL_SMO8800
145153 tristate "Dell Latitude freefall driver (ACPI SMO88XX)"
146154 depends on ACPI
drivers/platform/x86/Makefile+1−0
@@ -15,6 +15,7 @@ obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o · 14 unmodified lines
1515 obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
1616 obj-$(CONFIG_DELL_WMI) += dell-wmi.o
1717 obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
18+obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
1819 obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
1920 obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
2021 obj-$(CONFIG_ACER_WMI) += acer-wmi.o
drivers/platform/x86/dell-laptop.c+28−0
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include <linux/mm.h>
3030 #include <linux/i8042.h>
3131 #include <linux/debugfs.h>
32+#include <linux/dell-led.h>
3233 #include <linux/seq_file.h>
3334 #include <acpi/video.h>
3435 #include "dell-rbtn.h"
@@ -42,6 +43,8 @@ · 7 unmodified lines
4243 #define KBD_LED_AUTO_50_TOKEN 0x02EB
4344 #define KBD_LED_AUTO_75_TOKEN 0x02EC
4445 #define KBD_LED_AUTO_100_TOKEN 0x02F6
46+#define GLOBAL_MIC_MUTE_ENABLE 0x0364
47+#define GLOBAL_MIC_MUTE_DISABLE 0x0365
4548
4649 struct quirk_entry {
4750 u8 touchpad_led;
@@ -1978,6 +1981,31 @@ static void kbd_led_exit(void) · 1930 unmodified lines
19781981 led_classdev_unregister(&kbd_led);
19791982 }
19801983
1984+int dell_micmute_led_set(int state)
1985+{
1986+ struct calling_interface_buffer *buffer;
1987+ struct calling_interface_token *token;
1988+
1989+ if (state == 0)
1990+ token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
1991+ else if (state == 1)
1992+ token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
1993+ else
1994+ return -EINVAL;
1995+
1996+ if (!token)
1997+ return -ENODEV;
1998+
1999+ buffer = dell_smbios_get_buffer();
2000+ buffer->input[0] = token->location;
2001+ buffer->input[1] = token->value;
2002+ dell_smbios_send_request(1, 0);
2003+ dell_smbios_release_buffer();
2004+
2005+ return state;
2006+}
2007+EXPORT_SYMBOL_GPL(dell_micmute_led_set);
2008+
19812009 static int __init dell_init(void)
19822010 {
19832011 struct calling_interface_buffer *buffer;
drivers/platform/x86/dell-wmi-led.crenamed from drivers/leds/dell-led.c+33−108
@@ -1,6 +1,4 @@
11 /*
2− * dell_led.c - Dell LED Driver
3− *
42 * Copyright (C) 2010 Dell Inc.
53 * Louis Davis <louis_davis@dell.com>
64 * Jim Dailey <jim_dailey@dell.com>
@@ -15,16 +13,12 @@ · 8 unmodified lines
1513 #include <linux/leds.h>
1614 #include <linux/slab.h>
1715 #include <linux/module.h>
18−#include <linux/dmi.h>
19−#include <linux/dell-led.h>
20−#include "../platform/x86/dell-smbios.h"
2116
2217 MODULE_AUTHOR("Louis Davis/Jim Dailey");
2318 MODULE_DESCRIPTION("Dell LED Control Driver");
2419 MODULE_LICENSE("GPL");
2520
2621 #define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396"
27−#define DELL_APP_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
2822 MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
2923
3024 /* Error Result Codes: */
@@ -43,53 +37,6 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID); · 12 unmodified lines
4337 #define CMD_LED_OFF 17
4438 #define CMD_LED_BLINK 18
4539
46−#define GLOBAL_MIC_MUTE_ENABLE 0x364
47−#define GLOBAL_MIC_MUTE_DISABLE 0x365
48−
49−static int dell_micmute_led_set(int state)
50−{
51− struct calling_interface_buffer *buffer;
52− struct calling_interface_token *token;
53−
54− if (!wmi_has_guid(DELL_APP_GUID))
55− return -ENODEV;
56−
57− if (state == 0)
58− token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
59− else if (state == 1)
60− token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
61− else
62− return -EINVAL;
63−
64− if (!token)
65− return -ENODEV;
66−
67− buffer = dell_smbios_get_buffer();
68− buffer->input[0] = token->location;
69− buffer->input[1] = token->value;
70− dell_smbios_send_request(1, 0);
71− dell_smbios_release_buffer();
72−
73− return state;
74−}
75−
76−int dell_app_wmi_led_set(int whichled, int on)
77−{
78− int state = 0;
79−
80− switch (whichled) {
81− case DELL_LED_MICMUTE:
82− state = dell_micmute_led_set(on);
83− break;
84− default:
85− pr_warn("led type %x is not supported\n", whichled);
86− break;
87− }
88−
89− return state;
90−}
91−EXPORT_SYMBOL_GPL(dell_app_wmi_led_set);
92−
9340 struct bios_args {
9441 unsigned char length;
9542 unsigned char result_code;
@@ -99,37 +46,29 @@ struct bios_args { · 3 unmodified lines
9946 unsigned char off_time;
10047 };
10148
102−static int dell_led_perform_fn(u8 length,
103− u8 result_code,
104− u8 device_id,
105− u8 command,
106− u8 on_time,
107− u8 off_time)
49+static int dell_led_perform_fn(u8 length, u8 result_code, u8 device_id,
50+ u8 command, u8 on_time, u8 off_time)
10851 {
109− struct bios_args *bios_return;
110− u8 return_code;
111− union acpi_object *obj;
11252 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
53+ struct bios_args *bios_return;
11354 struct acpi_buffer input;
55+ union acpi_object *obj;
11456 acpi_status status;
57+ u8 return_code;
11558
116− struct bios_args args;
117− args.length = length;
118− args.result_code = result_code;
119− args.device_id = device_id;
120− args.command = command;
121− args.on_time = on_time;
122− args.off_time = off_time;
59+ struct bios_args args = {
60+ .length = length,
61+ .result_code = result_code,
62+ .device_id = device_id,
63+ .command = command,
64+ .on_time = on_time,
65+ .off_time = off_time
66+ };
12367
12468 input.length = sizeof(struct bios_args);
12569 input.pointer = &args;
12670
127− status = wmi_evaluate_method(DELL_LED_BIOS_GUID,
128− 1,
129− 1,
130− &input,
131− &output);
132−
71+ status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 1, 1, &input, &output);
13372 if (ACPI_FAILURE(status))
13473 return status;
13574
@@ -137,7 +76,7 @@ static int dell_led_perform_fn(u8 length, · 1 unmodified line
13776
13877 if (!obj)
13978 return -EINVAL;
140− else if (obj->type != ACPI_TYPE_BUFFER) {
79+ if (obj->type != ACPI_TYPE_BUFFER) {
14180 kfree(obj);
14281 return -EINVAL;
14382 }
@@ -170,8 +109,7 @@ static int led_off(void) · 26 unmodified lines
170109 0); /* not used */
171110 }
172111
173−static int led_blink(unsigned char on_eighths,
174− unsigned char off_eighths)
112+static int led_blink(unsigned char on_eighths, unsigned char off_eighths)
175113 {
176114 return dell_led_perform_fn(5, /* Length of command */
177115 INTERFACE_ERROR, /* Init to INTERFACE_ERROR */
@@ -182,7 +120,7 @@ static int led_blink(unsigned char on_eighths, · 4 unmodified lines
182120 }
183121
184122 static void dell_led_set(struct led_classdev *led_cdev,
185− enum led_brightness value)
123+ enum led_brightness value)
186124 {
187125 if (value == LED_OFF)
188126 led_off();
@@ -191,27 +129,22 @@ static void dell_led_set(struct led_classdev *led_cdev, · 2 unmodified lines
191129 }
192130
193131 static int dell_led_blink(struct led_classdev *led_cdev,
194− unsigned long *delay_on,
195− unsigned long *delay_off)
132+ unsigned long *delay_on, unsigned long *delay_off)
196133 {
197134 unsigned long on_eighths;
198135 unsigned long off_eighths;
199136
200− /* The Dell LED delay is based on 125ms intervals.
201− Need to round up to next interval. */
137+ /*
138+ * The Dell LED delay is based on 125ms intervals.
139+ * Need to round up to next interval.
140+ */
202141
203− on_eighths = (*delay_on + 124) / 125;
204− if (0 == on_eighths)
205− on_eighths = 1;
206− if (on_eighths > 255)
207− on_eighths = 255;
142+ on_eighths = DIV_ROUND_UP(*delay_on, 125);
143+ on_eighths = clamp_t(unsigned long, on_eighths, 1, 255);
208144 *delay_on = on_eighths * 125;
209145
210− off_eighths = (*delay_off + 124) / 125;
211− if (0 == off_eighths)
212− off_eighths = 1;
213− if (off_eighths > 255)
214− off_eighths = 255;
146+ off_eighths = DIV_ROUND_UP(*delay_off, 125);
147+ off_eighths = clamp_t(unsigned long, off_eighths, 1, 255);
215148 *delay_off = off_eighths * 125;
216149
217150 led_blink(on_eighths, off_eighths);
@@ -232,29 +165,21 @@ static int __init dell_led_init(void) · 14 unmodified lines
232165 {
233166 int error = 0;
234167
235− if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID))
168+ if (!wmi_has_guid(DELL_LED_BIOS_GUID))
236169 return -ENODEV;
237170
238− if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
239− error = led_off();
240− if (error != 0)
241− return -ENODEV;
242−
243− error = led_classdev_register(NULL, &dell_led);
244− }
171+ error = led_off();
172+ if (error != 0)
173+ return -ENODEV;
245174
246− return error;
175+ return led_classdev_register(NULL, &dell_led);
247176 }
248177
249178 static void __exit dell_led_exit(void)
250179 {
251− int error = 0;
180+ led_classdev_unregister(&dell_led);
252181
253− if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
254− error = led_off();
255− if (error == 0)
256− led_classdev_unregister(&dell_led);
257− }
182+ led_off();
258183 }
259184
260185 module_init(dell_led_init);
include/linux/dell-led.h+1−5
@@ -1,10 +1,6 @@
11 #ifndef __DELL_LED_H__
22 #define __DELL_LED_H__
33
4−enum {
5− DELL_LED_MICMUTE,
6−};
7−
8−int dell_app_wmi_led_set(int whichled, int on);
4+int dell_micmute_led_set(int on);
95
106 #endif
include/linux/leds-pca9532.h+2−2
@@ -22,7 +22,8 @@ enum pca9532_state { · 21 unmodified lines
2222 PCA9532_OFF = 0x0,
2323 PCA9532_ON = 0x1,
2424 PCA9532_PWM0 = 0x2,
25− PCA9532_PWM1 = 0x3
25+ PCA9532_PWM1 = 0x3,
26+ PCA9532_KEEP = 0xff,
2627 };
2728
2829 struct pca9532_led {
@@ -44,4 +45,3 @@ struct pca9532_platform_data { · 15 unmodified lines
4445 };
4546
4647 #endif /* __LINUX_PCA9532_H */
47−
include/linux/leds.h+10−4
@@ -122,10 +122,16 @@ struct led_classdev { · 121 unmodified lines
122122 struct mutex led_access;
123123 };
124124
125−extern int led_classdev_register(struct device *parent,
126− struct led_classdev *led_cdev);
127−extern int devm_led_classdev_register(struct device *parent,
128− struct led_classdev *led_cdev);
125+extern int of_led_classdev_register(struct device *parent,
126+ struct device_node *np,
127+ struct led_classdev *led_cdev);
128+#define led_classdev_register(parent, led_cdev) \
129+ of_led_classdev_register(parent, NULL, led_cdev)
130+extern int devm_of_led_classdev_register(struct device *parent,
131+ struct device_node *np,
132+ struct led_classdev *led_cdev);
133+#define devm_led_classdev_register(parent, led_cdev) \
134+ devm_of_led_classdev_register(parent, NULL, led_cdev)
129135 extern void led_classdev_unregister(struct led_classdev *led_cdev);
130136 extern void devm_led_classdev_unregister(struct device *parent,
131137 struct led_classdev *led_cdev);
include/linux/mfd/motorola-cpcap.h+3−0
@@ -14,6 +14,9 @@ · 13 unmodified lines
1414 * published by the Free Software Foundation.
1515 */
1616
17+#include <linux/device.h>
18+#include <linux/regmap.h>
19+
1720 #define CPCAP_VENDOR_ST 0
1821 #define CPCAP_VENDOR_TI 1
1922
sound/pci/hda/dell_wmi_helper.c+15−15
@@ -2,11 +2,11 @@ · 1 unmodified line
22 * to be included from codec driver
33 */
44
5−#if IS_ENABLED(CONFIG_LEDS_DELL_NETBOOKS)
5+#if IS_ENABLED(CONFIG_DELL_LAPTOP)
66 #include <linux/dell-led.h>
77
88 static int dell_led_value;
9−static int (*dell_led_set_func)(int, int);
9+static int (*dell_micmute_led_set_func)(int);
1010 static void (*dell_old_cap_hook)(struct hda_codec *,
1111 struct snd_kcontrol *,
1212 struct snd_ctl_elem_value *);
@@ -18,7 +18,7 @@ static void update_dell_wmi_micmute_led(struct hda_codec *codec, · 5 unmodified lines
1818 if (dell_old_cap_hook)
1919 dell_old_cap_hook(codec, kcontrol, ucontrol);
2020
21− if (!ucontrol || !dell_led_set_func)
21+ if (!ucontrol || !dell_micmute_led_set_func)
2222 return;
2323 if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
2424 /* TODO: How do I verify if it's a mono or stereo here? */
@@ -26,8 +26,8 @@ static void update_dell_wmi_micmute_led(struct hda_codec *codec, · 1 unmodified line
2626 if (val == dell_led_value)
2727 return;
2828 dell_led_value = val;
29− if (dell_led_set_func)
30− dell_led_set_func(DELL_LED_MICMUTE, dell_led_value);
29+ if (dell_micmute_led_set_func)
30+ dell_micmute_led_set_func(dell_led_value);
3131 }
3232 }
3333
@@ -39,15 +39,15 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec, · 5 unmodified lines
3939 bool removefunc = false;
4040
4141 if (action == HDA_FIXUP_ACT_PROBE) {
42− if (!dell_led_set_func)
43− dell_led_set_func = symbol_request(dell_app_wmi_led_set);
44− if (!dell_led_set_func) {
45− codec_warn(codec, "Failed to find dell wmi symbol dell_app_wmi_led_set\n");
42+ if (!dell_micmute_led_set_func)
43+ dell_micmute_led_set_func = symbol_request(dell_micmute_led_set);
44+ if (!dell_micmute_led_set_func) {
45+ codec_warn(codec, "Failed to find dell wmi symbol dell_micmute_led_set\n");
4646 return;
4747 }
4848
4949 removefunc = true;
50− if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) {
50+ if (dell_micmute_led_set_func(false) >= 0) {
5151 dell_led_value = 0;
5252 if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch)
5353 codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
@@ -60,17 +60,17 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec, · 6 unmodified lines
6060
6161 }
6262
63− if (dell_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
64− symbol_put(dell_app_wmi_led_set);
65− dell_led_set_func = NULL;
63+ if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
64+ symbol_put(dell_micmute_led_set);
65+ dell_micmute_led_set_func = NULL;
6666 dell_old_cap_hook = NULL;
6767 }
6868 }
6969
70−#else /* CONFIG_LEDS_DELL_NETBOOKS */
70+#else /* CONFIG_DELL_LAPTOP */
7171 static void alc_fixup_dell_wmi(struct hda_codec *codec,
7272 const struct hda_fixup *fix, int action)
7373 {
7474 }
7575
76−#endif /* CONFIG_LEDS_DELL_NETBOOKS */
76+#endif /* CONFIG_DELL_LAPTOP */