diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt index 747c53805eecf8e12bff3c18992d0c2a3f48e83b..68419843e32fc83c28ba7ecb5b0a25c2f4c2efb4 100644 --- a/Documentation/devicetree/bindings/leds/common.txt +++ b/Documentation/devicetree/bindings/leds/common.txt @@ -29,14 +29,23 @@ Optional properties for child nodes: "ide-disk" - LED indicates disk activity "timer" - LED flashes at a fixed, configurable rate -- max-microamp : maximum intensity in microamperes of the LED - (torch LED for flash devices) -- flash-max-microamp : maximum intensity in microamperes of the - flash LED; it is mandatory if the LED should - support the flash mode -- flash-timeout-us : timeout in microseconds after which the flash - LED is turned off +- led-max-microamp : Maximum LED supply current in microamperes. This property + can be made mandatory for the board configurations + introducing a risk of hardware damage in case an excessive + current is set. + For flash LED controllers with configurable current this + property is mandatory for the LEDs in the non-flash modes + (e.g. torch or indicator). +Required properties for flash LED child nodes: +- flash-max-microamp : Maximum flash LED supply current in microamperes. +- flash-max-timeout-us : Maximum timeout in microseconds after which the flash + LED is turned off. + +For controllers that have no configurable current the flash-max-microamp +property can be omitted. +For controllers that have no configurable timeout the flash-max-timeout-us +property can be omitted. Examples: @@ -49,7 +58,7 @@ system-status { camera-flash { label = "Flash"; led-sources = <0>, <1>; - max-microamp = <50000>; + led-max-microamp = <50000>; flash-max-microamp = <320000>; - flash-timeout-us = <500000>; + flash-max-timeout-us = <500000>; }; diff --git a/Documentation/devicetree/bindings/leds/leds-ns2.txt b/Documentation/devicetree/bindings/leds/leds-ns2.txt index aef3aca34d2d4272dbf49440bd32712a87e38c29..9f81258a5b6e9035835c0cb230559a5a6e7a68f0 100644 --- a/Documentation/devicetree/bindings/leds/leds-ns2.txt +++ b/Documentation/devicetree/bindings/leds/leds-ns2.txt @@ -8,6 +8,9 @@ Each LED is represented as a sub-node of the ns2-leds device. Required sub-node properties: - cmd-gpio: Command LED GPIO. See OF device-tree GPIO specification. - slow-gpio: Slow LED GPIO. See OF device-tree GPIO specification. +- modes-map: A mapping between LED modes (off, on or SATA activity blinking) and + the corresponding cmd-gpio/slow-gpio values. All the GPIO values combinations + should be given in order to avoid having an unknown mode at driver probe time. Optional sub-node properties: - label: Name for this LED. If omitted, the label is taken from the node name. @@ -15,6 +18,8 @@ Optional sub-node properties: Example: +#include <dt-bindings/leds/leds-ns2.h> + ns2-leds { compatible = "lacie,ns2-leds"; @@ -22,5 +27,9 @@ ns2-leds { label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = <NS_V2_LED_OFF 0 1 + NS_V2_LED_ON 1 0 + NS_V2_LED_ON 0 0 + NS_V2_LED_SATA 1 1>; }; }; diff --git a/MAINTAINERS b/MAINTAINERS index b41244b17775db111d1a6ce36aaa5d0527d7def1..cdcd9c5d3c0e5e0a6194ec87ddddae7533c97705 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6042,11 +6042,10 @@ F: Documentation/scsi/53c700.txt F: drivers/scsi/53c700* LED SUBSYSTEM -M: Bryan Wu <cooloney@gmail.com> M: Richard Purdie <rpurdie@rpsys.net> M: Jacek Anaszewski <j.anaszewski@samsung.com> L: linux-leds@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git S: Maintained F: drivers/leds/ F: include/linux/leds.h diff --git a/arch/arm/boot/dts/kirkwood-d2net.dts b/arch/arm/boot/dts/kirkwood-d2net.dts index 6b7856025001b376d575d133ace4e040a59ebddc..e1c25c35e9ce86a381558ba7cd610f81458697ef 100644 --- a/arch/arm/boot/dts/kirkwood-d2net.dts +++ b/arch/arm/boot/dts/kirkwood-d2net.dts @@ -10,6 +10,7 @@ /dts-v1/; +#include <dt-bindings/leds/leds-ns2.h> #include "kirkwood-netxbig.dtsi" / { @@ -28,6 +29,10 @@ label = "d2net_v2:blue:sata"; slow-gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>; cmd-gpio = <&gpio0 30 GPIO_ACTIVE_HIGH>; + modes-map = <NS_V2_LED_OFF 1 0 + NS_V2_LED_ON 0 1 + NS_V2_LED_ON 1 1 + NS_V2_LED_SATA 0 0>; }; }; diff --git a/arch/arm/boot/dts/kirkwood-is2.dts b/arch/arm/boot/dts/kirkwood-is2.dts index da674bbd49a8642524f89995102b86c7ec9f7bc0..4121674abd1c35fbca7212def1e08af3061317e2 100644 --- a/arch/arm/boot/dts/kirkwood-is2.dts +++ b/arch/arm/boot/dts/kirkwood-is2.dts @@ -1,5 +1,6 @@ /dts-v1/; +#include <dt-bindings/leds/leds-ns2.h> #include "kirkwood-ns2-common.dtsi" / { @@ -27,6 +28,10 @@ label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = <NS_V2_LED_OFF 1 0 + NS_V2_LED_ON 0 1 + NS_V2_LED_ON 1 1 + NS_V2_LED_SATA 0 0>; }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-ns2.dts b/arch/arm/boot/dts/kirkwood-ns2.dts index 53368d1022ccd6fbffc2ad86037a73f870f694bb..190189d235e60151bfd46b7835cce645a9c951d4 100644 --- a/arch/arm/boot/dts/kirkwood-ns2.dts +++ b/arch/arm/boot/dts/kirkwood-ns2.dts @@ -1,5 +1,6 @@ /dts-v1/; +#include <dt-bindings/leds/leds-ns2.h> #include "kirkwood-ns2-common.dtsi" / { @@ -27,6 +28,10 @@ label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = <NS_V2_LED_OFF 1 0 + NS_V2_LED_ON 0 1 + NS_V2_LED_ON 1 1 + NS_V2_LED_SATA 0 0>; }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-ns2max.dts b/arch/arm/boot/dts/kirkwood-ns2max.dts index 72c78d0b1116112cb224676073c57d534359a6b5..55cc41d9c80c2184d2580e43b5075b05113a8480 100644 --- a/arch/arm/boot/dts/kirkwood-ns2max.dts +++ b/arch/arm/boot/dts/kirkwood-ns2max.dts @@ -1,5 +1,6 @@ /dts-v1/; +#include <dt-bindings/leds/leds-ns2.h> #include "kirkwood-ns2-common.dtsi" / { @@ -46,6 +47,10 @@ label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = <NS_V2_LED_OFF 1 0 + NS_V2_LED_ON 0 1 + NS_V2_LED_ON 1 1 + NS_V2_LED_SATA 0 0>; }; }; }; diff --git a/arch/arm/boot/dts/kirkwood-ns2mini.dts b/arch/arm/boot/dts/kirkwood-ns2mini.dts index c441bf62c09fcfa9cab080b00eeb0e76129c31d0..9935f3ec29b4f6b026e580a3ce7cb9d3ac181115 100644 --- a/arch/arm/boot/dts/kirkwood-ns2mini.dts +++ b/arch/arm/boot/dts/kirkwood-ns2mini.dts @@ -1,5 +1,6 @@ /dts-v1/; +#include <dt-bindings/leds/leds-ns2.h> #include "kirkwood-ns2-common.dtsi" / { @@ -47,6 +48,10 @@ label = "ns2:blue:sata"; slow-gpio = <&gpio0 29 0>; cmd-gpio = <&gpio0 30 0>; + modes-map = <NS_V2_LED_OFF 1 0 + NS_V2_LED_ON 0 1 + NS_V2_LED_ON 1 1 + NS_V2_LED_SATA 0 0>; }; }; }; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9ad35f72ab4c077791cf7942cceb36301325872d..23408bd68fdc0c8b18f4e140bc367c2a07e53619 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -43,7 +43,7 @@ config LEDS_AAT1290 tristate "LED support for the AAT1290" depends on LEDS_CLASS_FLASH depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST depends on OF depends on PINCTRL help @@ -419,7 +419,7 @@ config LEDS_INTEL_SS4200 config LEDS_LT3593 tristate "LED driver for LT3593 controllers" depends on LEDS_CLASS - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help This option enables support for LEDs driven by a Linear Technology LT3593 controller. This controller uses a special one-wire pulse @@ -455,12 +455,16 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" depends on LEDS_CLASS - depends on MACH_KIRKWOOD + depends on MACH_KIRKWOOD || MACH_ARMADA_370 default y help - This option enable support for the dual-GPIO LED found on the - Network Space v2 board (and parents). This include Internet Space v2, - Network Space (Max) v2 and d2 Network v2 boards. + This option enables support for the dual-GPIO LEDs found on the + following LaCie/Seagate boards: + + Network Space v2 (and parents: Max, Mini) + Internet Space v2 + d2 Network v2 + n090401 (Seagate NAS 4-Bay) config LEDS_NETXBIG tristate "LED support for Big Network series LEDs" @@ -543,7 +547,8 @@ config LEDS_MENF21BMC config LEDS_KTD2692 tristate "LED support for KTD2692 flash LED controller" - depends on LEDS_CLASS_FLASH && GPIOLIB && OF + depends on LEDS_CLASS_FLASH && OF + depends on GPIOLIB || COMPILE_TEST help This option enables support for KTD2692 LED flash connected through ExpressWire interface. diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index beabfbc6f7cdd406f6ba96692bd5b376a893bdc4..ca51d58bed244c488d815003c366d03acf79e418 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -228,12 +228,15 @@ static int led_classdev_next_name(const char *init_name, char *name, { unsigned int i = 0; int ret = 0; + struct device *dev; strlcpy(name, init_name, len); - while (class_find_device(leds_class, NULL, name, match_name) && - (ret < len)) + while ((ret < len) && + (dev = class_find_device(leds_class, NULL, name, match_name))) { + put_device(dev); ret = snprintf(name, len, "%s_%u", init_name, ++i); + } if (ret >= len) return -ENOMEM; diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c index 2b4dc738dcd657092176822fc2613349e8066246..257a813c73f31ddf6b336a82895e7ca65fe7974d 100644 --- a/drivers/leds/leds-fsg.c +++ b/drivers/leds/leds-fsg.c @@ -156,63 +156,35 @@ static int fsg_led_probe(struct platform_device *pdev) latch_value = 0xffff; *latch_address = latch_value; - ret = led_classdev_register(&pdev->dev, &fsg_wlan_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_wlan_led); if (ret < 0) - goto failwlan; + return ret; - ret = led_classdev_register(&pdev->dev, &fsg_wan_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_wan_led); if (ret < 0) - goto failwan; + return ret; - ret = led_classdev_register(&pdev->dev, &fsg_sata_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_sata_led); if (ret < 0) - goto failsata; + return ret; - ret = led_classdev_register(&pdev->dev, &fsg_usb_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_usb_led); if (ret < 0) - goto failusb; + return ret; - ret = led_classdev_register(&pdev->dev, &fsg_sync_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_sync_led); if (ret < 0) - goto failsync; + return ret; - ret = led_classdev_register(&pdev->dev, &fsg_ring_led); + ret = devm_led_classdev_register(&pdev->dev, &fsg_ring_led); if (ret < 0) - goto failring; - - return ret; - - failring: - led_classdev_unregister(&fsg_sync_led); - failsync: - led_classdev_unregister(&fsg_usb_led); - failusb: - led_classdev_unregister(&fsg_sata_led); - failsata: - led_classdev_unregister(&fsg_wan_led); - failwan: - led_classdev_unregister(&fsg_wlan_led); - failwlan: + return ret; return ret; } -static int fsg_led_remove(struct platform_device *pdev) -{ - led_classdev_unregister(&fsg_wlan_led); - led_classdev_unregister(&fsg_wan_led); - led_classdev_unregister(&fsg_sata_led); - led_classdev_unregister(&fsg_usb_led); - led_classdev_unregister(&fsg_sync_led); - led_classdev_unregister(&fsg_ring_led); - - return 0; -} - - static struct platform_driver fsg_led_driver = { .probe = fsg_led_probe, - .remove = fsg_led_remove, .driver = { .name = "fsg-led", }, diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 91325de3cd3305ad589820ff07bf44cd99e36a4a..b38430cb10ad0a8de7082745732ddf8d49ed6796 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -492,7 +492,6 @@ static struct i2c_driver lm3530_i2c_driver = { .id_table = lm3530_id, .driver = { .name = LM3530_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index f5112cb2d9915359957b2b90f432dee11918778b..48872997d6b4b35391affa52d07496082fb261f7 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c @@ -555,7 +555,6 @@ MODULE_DEVICE_TABLE(i2c, lm355x_id); static struct i2c_driver lm355x_i2c_driver = { .driver = { .name = LM355x_NAME, - .owner = THIS_MODULE, .pm = NULL, }, .probe = lm355x_probe, diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c index d3dec0132769dd1d2e648a1bb69d5a78029a1461..02ebe342f5af219ae4bd576a78794adc5d6fc88f 100644 --- a/drivers/leds/leds-lm3642.c +++ b/drivers/leds/leds-lm3642.c @@ -446,7 +446,6 @@ MODULE_DEVICE_TABLE(i2c, lm3642_id); static struct i2c_driver lm3642_i2c_driver = { .driver = { .name = LM3642_NAME, - .owner = THIS_MODULE, .pm = NULL, }, .probe = lm3642_probe, diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 8ca197af2864841391edb94aaee13c85c60854ea..63a92542c8cb0953d17d5dcd8502075348dad9cf 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -514,20 +514,19 @@ static int lp5521_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata; + struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; - if (!dev_get_platdata(&client->dev)) { + if (!pdata) { if (np) { - ret = lp55xx_of_populate_pdata(&client->dev, np); - if (ret < 0) - return ret; + pdata = lp55xx_of_populate_pdata(&client->dev, np); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } else { dev_err(&client->dev, "no platform data\n"); return -EINVAL; } } - pdata = dev_get_platdata(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 584dbbcec65955d49f8e9603e129b1c0f83c2122..1d0187f42941aadfd91eb7b17d36b876484fff51 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -880,20 +880,19 @@ static int lp5523_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata; + struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; - if (!dev_get_platdata(&client->dev)) { + if (!pdata) { if (np) { - ret = lp55xx_of_populate_pdata(&client->dev, np); - if (ret < 0) - return ret; + pdata = lp55xx_of_populate_pdata(&client->dev, np); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } else { dev_err(&client->dev, "no platform data\n"); return -EINVAL; } } - pdata = dev_get_platdata(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index ca85724ab138b30997f3afc643dbeb6fe590d37b..0360c59dbdc91b122d0d08273c48203e6755ca6b 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -515,20 +515,19 @@ static int lp5562_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata; + struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; - if (!dev_get_platdata(&client->dev)) { + if (!pdata) { if (np) { - ret = lp55xx_of_populate_pdata(&client->dev, np); - if (ret < 0) - return ret; + pdata = lp55xx_of_populate_pdata(&client->dev, np); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } else { dev_err(&client->dev, "no platform data\n"); return -EINVAL; } } - pdata = dev_get_platdata(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 96d51e9879c905d2c4eb6bac2325af174665a9f1..59b76833f0d32d1d114421ed17b160fd60d2a9c2 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -543,7 +543,8 @@ void lp55xx_unregister_sysfs(struct lp55xx_chip *chip) } EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs); -int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) +struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, + struct device_node *np) { struct device_node *child; struct lp55xx_platform_data *pdata; @@ -553,17 +554,17 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) - return -ENOMEM; + return ERR_PTR(-ENOMEM); num_channels = of_get_child_count(np); if (num_channels == 0) { dev_err(dev, "no LED channels\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL); if (!cfg) - return -ENOMEM; + return ERR_PTR(-ENOMEM); pdata->led_config = &cfg[0]; pdata->num_channels = num_channels; @@ -588,9 +589,7 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) /* LP8501 specific */ of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel); - dev->platform_data = pdata; - - return 0; + return pdata; } EXPORT_SYMBOL_GPL(lp55xx_of_populate_pdata); diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h index cceab483edd04a14174224a0d8b253a738376e66..c7f1e6155001f6eeb76818f6a4dcf3904624c7e8 100644 --- a/drivers/leds/leds-lp55xx-common.h +++ b/drivers/leds/leds-lp55xx-common.h @@ -202,7 +202,7 @@ extern int lp55xx_register_sysfs(struct lp55xx_chip *chip); extern void lp55xx_unregister_sysfs(struct lp55xx_chip *chip); /* common device tree population function */ -extern int lp55xx_of_populate_pdata(struct device *dev, - struct device_node *np); +extern struct lp55xx_platform_data +*lp55xx_of_populate_pdata(struct device *dev, struct device_node *np); #endif /* _LEDS_LP55XX_COMMON_H */ diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index d3098e395fff469c30950ce73542519f6f880c80..3f54f6f2b821d2684f326cda03ac1957ac1015ef 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -308,20 +308,19 @@ static int lp8501_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata; + struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; - if (!dev_get_platdata(&client->dev)) { + if (!pdata) { if (np) { - ret = lp55xx_of_populate_pdata(&client->dev, np); - if (ret < 0) - return ret; + pdata = lp55xx_of_populate_pdata(&client->dev, np); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } else { dev_err(&client->dev, "no platform data\n"); return -EINVAL; } } - pdata = dev_get_platdata(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 8c2b7fbe23924fcdf45cf02976112e95274c91fd..79f084354e679930f1efa36f30745e867ed72b27 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -302,7 +302,7 @@ static int lp8860_init(struct lp8860_led *led) return ret; } -static struct reg_default lp8860_reg_defs[] = { +static const struct reg_default lp8860_reg_defs[] = { { LP8860_DISP_CL1_BRT_MSB, 0x00}, { LP8860_DISP_CL1_BRT_LSB, 0x00}, { LP8860_DISP_CL1_CURR_MSB, 0x00}, @@ -332,7 +332,7 @@ static const struct regmap_config lp8860_regmap_config = { .cache_type = REGCACHE_NONE, }; -static struct reg_default lp8860_eeprom_defs[] = { +static const struct reg_default lp8860_eeprom_defs[] = { { LP8860_EEPROM_REG_0, 0x00 }, { LP8860_EEPROM_REG_1, 0x00 }, { LP8860_EEPROM_REG_2, 0x00 }, diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 1fd6adbb43b7937637fe0a048a37e1bac8c669b0..b33514d9f427e279bf091abab4126f55e0d48182 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -31,50 +31,38 @@ #include <linux/platform_data/leds-kirkwood-ns2.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include "leds.h" /* - * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in - * relation with the SATA activity. This capability is exposed through the - * "sata" sysfs attribute. - * - * The following array detail the different LED registers and the combination - * of their possible values: - * - * cmd_led | slow_led | /SATA active | LED state - * | | | - * 1 | 0 | x | off - * - | 1 | x | on - * 0 | 0 | 1 | on - * 0 | 0 | 0 | blink (rate 300ms) + * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED + * modes are available: off, on and SATA activity blinking. The LED modes are + * controlled through two GPIOs (command and slow): each combination of values + * for the command/slow GPIOs corresponds to a LED mode. */ -enum ns2_led_modes { - NS_V2_LED_OFF, - NS_V2_LED_ON, - NS_V2_LED_SATA, -}; - -struct ns2_led_mode_value { - enum ns2_led_modes mode; - int cmd_level; - int slow_level; -}; - -static struct ns2_led_mode_value ns2_led_modval[] = { - { NS_V2_LED_OFF , 1, 0 }, - { NS_V2_LED_ON , 0, 1 }, - { NS_V2_LED_ON , 1, 1 }, - { NS_V2_LED_SATA, 0, 0 }, -}; - struct ns2_led_data { struct led_classdev cdev; unsigned cmd; unsigned slow; + bool can_sleep; + int mode_index; unsigned char sata; /* True when SATA mode active. */ rwlock_t rw_lock; /* Lock GPIOs. */ + struct work_struct work; + int num_modes; + struct ns2_led_modval *modval; }; +static void ns2_led_work(struct work_struct *work) +{ + struct ns2_led_data *led_dat = + container_of(work, struct ns2_led_data, work); + int i = led_dat->mode_index; + + gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level); + gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level); +} + static int ns2_led_get_mode(struct ns2_led_data *led_dat, enum ns2_led_modes *mode) { @@ -83,22 +71,18 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat, int cmd_level; int slow_level; - read_lock_irq(&led_dat->rw_lock); + cmd_level = gpio_get_value_cansleep(led_dat->cmd); + slow_level = gpio_get_value_cansleep(led_dat->slow); - cmd_level = gpio_get_value(led_dat->cmd); - slow_level = gpio_get_value(led_dat->slow); - - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { - if (cmd_level == ns2_led_modval[i].cmd_level && - slow_level == ns2_led_modval[i].slow_level) { - *mode = ns2_led_modval[i].mode; + for (i = 0; i < led_dat->num_modes; i++) { + if (cmd_level == led_dat->modval[i].cmd_level && + slow_level == led_dat->modval[i].slow_level) { + *mode = led_dat->modval[i].mode; ret = 0; break; } } - read_unlock_irq(&led_dat->rw_lock); - return ret; } @@ -106,19 +90,32 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat, enum ns2_led_modes mode) { int i; + bool found = false; unsigned long flags; + for (i = 0; i < led_dat->num_modes; i++) + if (mode == led_dat->modval[i].mode) { + found = true; + break; + } + + if (!found) + return; + write_lock_irqsave(&led_dat->rw_lock, flags); - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { - if (mode == ns2_led_modval[i].mode) { - gpio_set_value(led_dat->cmd, - ns2_led_modval[i].cmd_level); - gpio_set_value(led_dat->slow, - ns2_led_modval[i].slow_level); - } + if (!led_dat->can_sleep) { + gpio_set_value(led_dat->cmd, + led_dat->modval[i].cmd_level); + gpio_set_value(led_dat->slow, + led_dat->modval[i].slow_level); + goto exit_unlock; } + led_dat->mode_index = i; + schedule_work(&led_dat->work); + +exit_unlock: write_unlock_irqrestore(&led_dat->rw_lock, flags); } @@ -148,7 +145,6 @@ static ssize_t ns2_led_sata_store(struct device *dev, container_of(led_cdev, struct ns2_led_data, cdev); int ret; unsigned long enable; - enum ns2_led_modes mode; ret = kstrtoul(buff, 10, &enable); if (ret < 0) @@ -157,19 +153,19 @@ static ssize_t ns2_led_sata_store(struct device *dev, enable = !!enable; if (led_dat->sata == enable) - return count; + goto exit; - ret = ns2_led_get_mode(led_dat, &mode); - if (ret < 0) - return ret; + led_dat->sata = enable; + + if (!led_get_brightness(led_cdev)) + goto exit; - if (enable && mode == NS_V2_LED_ON) + if (enable) ns2_led_set_mode(led_dat, NS_V2_LED_SATA); - if (!enable && mode == NS_V2_LED_SATA) + else ns2_led_set_mode(led_dat, NS_V2_LED_ON); - led_dat->sata = enable; - +exit: return count; } @@ -199,7 +195,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, enum ns2_led_modes mode; ret = devm_gpio_request_one(&pdev->dev, template->cmd, - gpio_get_value(template->cmd) ? + gpio_get_value_cansleep(template->cmd) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, template->name); if (ret) { @@ -209,7 +205,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, } ret = devm_gpio_request_one(&pdev->dev, template->slow, - gpio_get_value(template->slow) ? + gpio_get_value_cansleep(template->slow) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, template->name); if (ret) { @@ -228,6 +224,10 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, led_dat->cdev.groups = ns2_led_groups; led_dat->cmd = template->cmd; led_dat->slow = template->slow; + led_dat->can_sleep = gpio_cansleep(led_dat->cmd) | + gpio_cansleep(led_dat->slow); + led_dat->modval = template->modval; + led_dat->num_modes = template->num_modes; ret = ns2_led_get_mode(led_dat, &mode); if (ret < 0) @@ -238,6 +238,8 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, led_dat->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; + INIT_WORK(&led_dat->work, ns2_led_work); + ret = led_classdev_register(&pdev->dev, &led_dat->cdev); if (ret < 0) return ret; @@ -248,6 +250,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, static void delete_ns2_led(struct ns2_led_data *led_dat) { led_classdev_unregister(&led_dat->cdev); + cancel_work_sync(&led_dat->work); } #ifdef CONFIG_OF_GPIO @@ -259,9 +262,8 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) { struct device_node *np = dev->of_node; struct device_node *child; - struct ns2_led *leds; + struct ns2_led *led, *leds; int num_leds = 0; - int i = 0; num_leds = of_get_child_count(np); if (!num_leds) @@ -272,26 +274,57 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) if (!leds) return -ENOMEM; + led = leds; for_each_child_of_node(np, child) { const char *string; - int ret; + int ret, i, num_modes; + struct ns2_led_modval *modval; ret = of_get_named_gpio(child, "cmd-gpio", 0); if (ret < 0) return ret; - leds[i].cmd = ret; + led->cmd = ret; ret = of_get_named_gpio(child, "slow-gpio", 0); if (ret < 0) return ret; - leds[i].slow = ret; + led->slow = ret; ret = of_property_read_string(child, "label", &string); - leds[i].name = (ret == 0) ? string : child->name; + led->name = (ret == 0) ? string : child->name; ret = of_property_read_string(child, "linux,default-trigger", &string); if (ret == 0) - leds[i].default_trigger = string; + led->default_trigger = string; + + ret = of_property_count_u32_elems(child, "modes-map"); + if (ret < 0 || ret % 3) { + dev_err(dev, + "Missing or malformed modes-map property\n"); + return -EINVAL; + } + + num_modes = ret / 3; + modval = devm_kzalloc(dev, + num_modes * sizeof(struct ns2_led_modval), + GFP_KERNEL); + if (!modval) + return -ENOMEM; + + for (i = 0; i < num_modes; i++) { + of_property_read_u32_index(child, + "modes-map", 3 * i, + (u32 *) &modval[i].mode); + of_property_read_u32_index(child, + "modes-map", 3 * i + 1, + (u32 *) &modval[i].cmd_level); + of_property_read_u32_index(child, + "modes-map", 3 * i + 2, + (u32 *) &modval[i].slow_level); + } + + led->num_modes = num_modes; + led->modval = modval; - i++; + led++; } pdata->leds = leds; diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index c3a08b60535bc31048d1246c1d5ef01dd5c12c6b..b775e1efecd3b6711acd61847652caf2352f194c 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -379,7 +379,6 @@ static int pca955x_remove(struct i2c_client *client) static struct i2c_driver pca955x_driver = { .driver = { .name = "leds-pca955x", - .owner = THIS_MODULE, }, .probe = pca955x_probe, .remove = pca955x_remove, diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index bee3e1ab27fd92fd7b71ab0a34812cd80ac5c8d0..41f269fe09205f48c3216179d30da652a4574bb3 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -332,6 +332,7 @@ static const struct of_device_id of_pca963x_match[] = { { .compatible = "nxp,pca9635", }, {}, }; +MODULE_DEVICE_TABLE(of, of_pca963x_match); #else static struct pca963x_platform_data * pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip) @@ -458,7 +459,6 @@ static int pca963x_remove(struct i2c_client *client) static struct i2c_driver pca963x_driver = { .driver = { .name = "leds-pca963x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_pca963x_match), }, .probe = pca963x_probe, diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index d1660b0398125943b58822401d350b9ce983d5f2..b88900d721e4494e9e05c494e7d9977501cda97b 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -83,9 +83,9 @@ static int syscon_led_probe(struct platform_device *pdev) return -ENODEV; } map = syscon_node_to_regmap(parent->of_node); - if (!map) { + if (IS_ERR(map)) { dev_err(dev, "no regmap for syscon LED parent\n"); - return -ENODEV; + return PTR_ERR(map); } sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 20fa8e77f1863c5aa9bbe78a5eb028d6c32cc49c..edbecc4ca2da4c2df887e56c34fcee33c88ca847 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -735,6 +735,7 @@ static const struct of_device_id of_tca6507_leds_match[] = { { .compatible = "ti,tca6507", }, {}, }; +MODULE_DEVICE_TABLE(of, of_tca6507_leds_match); #else static struct tca6507_platform_data * @@ -830,7 +831,6 @@ static int tca6507_remove(struct i2c_client *client) static struct i2c_driver tca6507_driver = { .driver = { .name = "leds-tca6507", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_tca6507_leds_match), }, .probe = tca6507_probe, diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index de16c29d7895412ce48368b4b01a011b0449e587..b806eca83d27ede6ead3c08568a221767fd8bbae 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -231,10 +231,6 @@ tlc591xx_probe(struct i2c_client *client, if (!count || count > tlc591xx->max_leds) return -EINVAL; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 49794b47b51c498daa4921c2616693af92eaf2fd..5bda6a9b56bbd90b4a3749f87bc0c6fda8dd5034 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -72,7 +72,7 @@ config LEDS_TRIGGER_CPU config LEDS_TRIGGER_GPIO tristate "LED GPIO Trigger" depends on LEDS_TRIGGERS - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help This allows LEDs to be controlled by gpio events. It's good when using gpios as switches and triggering the needed LEDs diff --git a/include/dt-bindings/leds/leds-ns2.h b/include/dt-bindings/leds/leds-ns2.h new file mode 100644 index 0000000000000000000000000000000000000000..491c5f974a92c7d1f69f12fa48b0a4a0f3263ac5 --- /dev/null +++ b/include/dt-bindings/leds/leds-ns2.h @@ -0,0 +1,8 @@ +#ifndef _DT_BINDINGS_LEDS_NS2_H +#define _DT_BINDINGS_LEDS_NS2_H + +#define NS_V2_LED_OFF 0 +#define NS_V2_LED_ON 1 +#define NS_V2_LED_SATA 2 + +#endif diff --git a/include/linux/platform_data/leds-kirkwood-ns2.h b/include/linux/platform_data/leds-kirkwood-ns2.h index 6a9fed57f34620c20a931f317150e5a381058e8f..eb8a6860e81691085e1735ce565a37a28bbfd7d3 100644 --- a/include/linux/platform_data/leds-kirkwood-ns2.h +++ b/include/linux/platform_data/leds-kirkwood-ns2.h @@ -9,11 +9,25 @@ #ifndef __LEDS_KIRKWOOD_NS2_H #define __LEDS_KIRKWOOD_NS2_H +enum ns2_led_modes { + NS_V2_LED_OFF, + NS_V2_LED_ON, + NS_V2_LED_SATA, +}; + +struct ns2_led_modval { + enum ns2_led_modes mode; + int cmd_level; + int slow_level; +}; + struct ns2_led { const char *name; const char *default_trigger; unsigned cmd; unsigned slow; + int num_modes; + struct ns2_led_modval *modval; }; struct ns2_led_platform_data {