From 7542a04b1515f0f878b267beb233c4ef067243fb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 23 Apr 2013 04:52:59 -0700 Subject: leds: lp55xx: add support for Device Tree bindings This patch allows the lp5521 driver to be successfully probed and initialised when Device Tree support is enabled. Based on a patch by Gabriel Fernandez, rewritten in accordance with review feedback. Cc: Gabriel Fernandez Signed-off-by: Linus Walleij Acked-by: Milo Kim Signed-off-by: Bryan Wu diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt new file mode 100644 index 0000000..348c88e --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt @@ -0,0 +1,21 @@ +Binding for National Semiconductor LP55xx Led Drivers + +Required properties: +- compatible: "national,lp5521" or "national,lp5523" +- label: Used for naming LEDs +- num-channel: Number of LED channels +- led-cur: Current setting at each led channel (mA x10, 0 if led is not connected) +- max-cur: Maximun current at each led channel. +- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) + +example: + +lp5521@32 { + compatible = "national,lp5521"; + reg = <0x32>; + label = "lp5521_pri"; + num-channel = /bits/ 8 <3>; + led-cur = /bits/ 8 <0x2f 0x2f 0x2f>; + max-cur = /bits/ 8 <0x5f 0x5f 0x5f>; + clock-mode = /bits/8 <2>; +}; diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 19752c9..d461e26 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "leds-lp55xx-common.h" @@ -416,12 +417,20 @@ static int lp5521_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata = client->dev.platform_data; - - if (!pdata) { - dev_err(&client->dev, "no platform data\n"); - return -EINVAL; + struct lp55xx_platform_data *pdata; + struct device_node *np = client->dev.of_node; + + if (!client->dev.platform_data) { + if (np) { + ret = lp55xx_of_populate_pdata(&client->dev, np); + if (ret < 0) + return ret; + } else { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } } + pdata = client->dev.platform_data; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -481,6 +490,7 @@ static int lp5521_remove(struct i2c_client *client) static const struct i2c_device_id lp5521_id[] = { { "lp5521", 0 }, /* Three channel chip */ + { "national,lp5521", 0 }, /* OF compatible */ { } }; MODULE_DEVICE_TABLE(i2c, lp5521_id); diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 229f734..365e914 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -429,12 +429,20 @@ static int lp5523_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata = client->dev.platform_data; - - if (!pdata) { - dev_err(&client->dev, "no platform data\n"); - return -EINVAL; + struct lp55xx_platform_data *pdata; + struct device_node *np = client->dev.of_node; + + if (!client->dev.platform_data) { + if (np) { + ret = lp55xx_of_populate_pdata(&client->dev, np); + if (ret < 0) + return ret; + } else { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } } + pdata = client->dev.platform_data; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -495,6 +503,7 @@ static int lp5523_remove(struct i2c_client *client) static const struct i2c_device_id lp5523_id[] = { { "lp5523", LP5523 }, { "lp55231", LP55231 }, + { "national,lp5523", 0 }, /* OF compatible */ { } }; diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index ba34199..a0d2bd2 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "leds-lp55xx-common.h" @@ -554,6 +555,59 @@ 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 *pdata; + u8 led_cur[3]; + u8 max_cur[3]; + u8 clock_mode; + u8 num_channel; + const char *label; + struct lp55xx_led_config *led_config; + int ret; + int i; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = of_property_read_u8(np, "num-channel", &num_channel); + if (ret < 0) + return ret; + ret = of_property_read_u8_array(np, "led-cur", led_cur, num_channel); + if (ret < 0) + return ret; + ret = of_property_read_u8_array(np, "max-cur", max_cur, num_channel); + if (ret < 0) + return ret; + ret = of_property_read_string(np, "label", &label); + if (ret < 0) + return ret; + ret = of_property_read_u8_array(np, "clock-mode", &clock_mode, 1); + if (ret < 0) + return ret; + + led_config = devm_kzalloc(dev, sizeof(*led_config) * num_channel, + GFP_KERNEL); + if (!led_config) + return -ENOMEM; + + for (i = 0; i < num_channel; i++) { + led_config[i].chan_nr = i; + led_config[i].led_current = led_cur[i]; + led_config[i].max_current = max_cur[i]; + } + pdata->label = kzalloc(sizeof(char) * 32, GFP_KERNEL); + strcpy((char *)pdata->label, (char *) label); + pdata->led_config = &led_config[0]; + pdata->num_channels = num_channel; + pdata->clock_mode = clock_mode; + dev->platform_data = pdata; + + return 0; +} +EXPORT_SYMBOL_GPL(lp55xx_of_populate_pdata); + MODULE_AUTHOR("Milo Kim "); MODULE_DESCRIPTION("LP55xx Common Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h index fa6a078..dbbf86d 100644 --- a/drivers/leds/leds-lp55xx-common.h +++ b/drivers/leds/leds-lp55xx-common.h @@ -135,4 +135,8 @@ extern void lp55xx_unregister_leds(struct lp55xx_led *led, 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); + #endif /* _LEDS_LP55XX_COMMON_H */ -- cgit v0.10.2 From a0f50b52badd39aaa3ff98f52ea91b07bdee80a7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 2 May 2013 23:43:17 -0700 Subject: leds: atmel-pwm: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c index 8a39c5b..90518f8 100644 --- a/drivers/leds/leds-atmel-pwm.c +++ b/drivers/leds/leds-atmel-pwm.c @@ -129,7 +129,6 @@ static int pwmled_remove(struct platform_device *pdev) pwm_channel_free(&led->pwmc); } - platform_set_drvdata(pdev, NULL); return 0; } -- cgit v0.10.2 From d9041d5886f9c0cd33dd320d2bd98f8626d50725 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 2 May 2013 23:43:44 -0700 Subject: leds: leds-gpio: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index b02b679..02c4cc1 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -282,8 +282,6 @@ static int gpio_led_remove(struct platform_device *pdev) for (i = 0; i < priv->num_leds; i++) delete_gpio_led(&priv->leds[i]); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit v0.10.2 From cda7f61e269fad3ecfa07918e2587a2c6da89761 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 2 May 2013 23:44:01 -0700 Subject: leds: leds-mc13783: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index e942ada..ea8fc5d 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -371,7 +371,6 @@ static int mc13783_led_remove(struct platform_device *pdev) mc13xxx_unlock(dev); - platform_set_drvdata(pdev, NULL); return 0; } -- cgit v0.10.2 From a036e4cde5f29da010ead845569ff1e1ecc32d2a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 2 May 2013 23:44:46 -0700 Subject: leds: leds-ns2: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 70137b1..e7df987 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -374,8 +374,6 @@ static int ns2_led_remove(struct platform_device *pdev) for (i = 0; i < priv->num_leds; i++) delete_ns2_led(&priv->leds_data[i]); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit v0.10.2 From 2dac912809490ea3a6e5c16b83b54a08f36fc3d9 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Tue, 7 May 2013 00:14:48 -0700 Subject: leds: lp55xx: support dynamic channel settings in the device tree structure Currently, the LP55xx DT structure supports max 3 channels. However, LP5523 has max 9 channels and LP5562 has 4 channels. To enhance this constraint, the DT structure has been changed. (a) Use the child node for various channel settings instead of fixed array (b) Remove 'num_channel' property. This value can be retrieved by counting the children node. (c) 'chan-name' property supported (d) Documentation updates for LP5521 and LP5523 (cooloney@gmail.com: fix a coding style issue in leds-lp55xx.txt) Cc: Gabriel Fernandez Signed-off-by: Milo(Woogyom) Kim Reviewed-by: Linus Walleij Signed-off-by: Bryan Wu diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt index 348c88e..1ed6bb0 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt @@ -2,20 +2,113 @@ Binding for National Semiconductor LP55xx Led Drivers Required properties: - compatible: "national,lp5521" or "national,lp5523" -- label: Used for naming LEDs -- num-channel: Number of LED channels +- reg: I2C slave address +- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) + +Each child has own specific current settings - led-cur: Current setting at each led channel (mA x10, 0 if led is not connected) - max-cur: Maximun current at each led channel. -- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) -example: +Optional properties: +- label: Used for naming LEDs + +Alternatively, each child can have specific channel name +- chan-name: Name of each channel name + +example 1) LP5521 +3 LED channels, external clock used. Channel names are 'lp5521_pri:channel0', +'lp5521_pri:channel1' and 'lp5521_pri:channel2' lp5521@32 { compatible = "national,lp5521"; reg = <0x32>; label = "lp5521_pri"; - num-channel = /bits/ 8 <3>; - led-cur = /bits/ 8 <0x2f 0x2f 0x2f>; - max-cur = /bits/ 8 <0x5f 0x5f 0x5f>; - clock-mode = /bits/8 <2>; + clock-mode = /bits/ 8 <2>; + + chan0 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + }; + + chan1 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + }; + + chan2 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + }; +}; + +example 2) LP5523 +9 LED channels with specific name. Internal clock used. +The I2C slave address is configurable with ASEL1 and ASEL0 pins. +Available addresses are 32/33/34/35h. + +ASEL1 ASEL0 Address +------------------------- + GND GND 32h + GND VEN 33h + VEN GND 34h + VEN VEN 35h + +lp5523@32 { + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = /bits/ 8 <1>; + + chan0 { + chan-name = "d1"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan1 { + chan-name = "d2"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan2 { + chan-name = "d3"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan3 { + chan-name = "d4"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan4 { + chan-name = "d5"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan5 { + chan-name = "d6"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan6 { + chan-name = "d7"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan7 { + chan-name = "d8"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan8 { + chan-name = "d9"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; }; diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index a0d2bd2..c2fecd4 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -557,51 +557,42 @@ EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs); int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) { + struct device_node *child; struct lp55xx_platform_data *pdata; - u8 led_cur[3]; - u8 max_cur[3]; - u8 clock_mode; - u8 num_channel; - const char *label; - struct lp55xx_led_config *led_config; - int ret; - int i; + struct lp55xx_led_config *cfg; + int num_channels; + int i = 0; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - ret = of_property_read_u8(np, "num-channel", &num_channel); - if (ret < 0) - return ret; - ret = of_property_read_u8_array(np, "led-cur", led_cur, num_channel); - if (ret < 0) - return ret; - ret = of_property_read_u8_array(np, "max-cur", max_cur, num_channel); - if (ret < 0) - return ret; - ret = of_property_read_string(np, "label", &label); - if (ret < 0) - return ret; - ret = of_property_read_u8_array(np, "clock-mode", &clock_mode, 1); - if (ret < 0) - return ret; + num_channels = of_get_child_count(np); + if (num_channels == 0) { + dev_err(dev, "no LED channels\n"); + return -EINVAL; + } - led_config = devm_kzalloc(dev, sizeof(*led_config) * num_channel, - GFP_KERNEL); - if (!led_config) + cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL); + if (!cfg) return -ENOMEM; - for (i = 0; i < num_channel; i++) { - led_config[i].chan_nr = i; - led_config[i].led_current = led_cur[i]; - led_config[i].max_current = max_cur[i]; + pdata->led_config = &cfg[0]; + pdata->num_channels = num_channels; + + for_each_child_of_node(np, child) { + cfg[i].chan_nr = i; + + of_property_read_string(child, "chan-name", &cfg[i].name); + of_property_read_u8(child, "led-cur", &cfg[i].led_current); + of_property_read_u8(child, "max-cur", &cfg[i].max_current); + + i++; } - pdata->label = kzalloc(sizeof(char) * 32, GFP_KERNEL); - strcpy((char *)pdata->label, (char *) label); - pdata->led_config = &led_config[0]; - pdata->num_channels = num_channel; - pdata->clock_mode = clock_mode; + + of_property_read_string(np, "label", &pdata->label); + of_property_read_u8(np, "clock-mode", &pdata->clock_mode); + dev->platform_data = pdata; return 0; -- cgit v0.10.2 From e015050cc5ea01e4beba3862dcafef9360c77522 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Tue, 7 May 2013 00:14:49 -0700 Subject: leds: lp5562: support the device tree feature The LP55xx DT structure is applicable to the LP5562 device. The driver and documentation are updated. Compatible property of the DT : LP5521 and LP5223 were manufactured by National Semiconductor. LP5562 is a new device from Texas Instruments. Cc: Gabriel Fernandez Signed-off-by: Milo(Woogyom) Kim Acked-by: Linus Walleij Signed-off-by: Bryan Wu diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt index 1ed6bb0..d517688 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt @@ -1,7 +1,7 @@ -Binding for National Semiconductor LP55xx Led Drivers +Binding for TI/National Semiconductor LP55xx Led Drivers Required properties: -- compatible: "national,lp5521" or "national,lp5523" +- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" - reg: I2C slave address - clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) @@ -112,3 +112,36 @@ lp5523@32 { max-cur = /bits/ 8 <0x20>; }; }; + +example 3) LP5562 +4 channels are defined. + +lp5562@30 { + compatible = "ti,lp5562"; + reg = <0x30>; + clock-mode = /bits/8 <2>; + + chan0 { + chan-name = "R"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan1 { + chan-name = "G"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan2 { + chan-name = "B"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan3 { + chan-name = "W"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; +}; diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 513f239..e53bcb8 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -515,12 +515,20 @@ static int lp5562_probe(struct i2c_client *client, int ret; struct lp55xx_chip *chip; struct lp55xx_led *led; - struct lp55xx_platform_data *pdata = client->dev.platform_data; - - if (!pdata) { - dev_err(&client->dev, "no platform data\n"); - return -EINVAL; + struct lp55xx_platform_data *pdata; + struct device_node *np = client->dev.of_node; + + if (!client->dev.platform_data) { + if (np) { + ret = lp55xx_of_populate_pdata(&client->dev, np); + if (ret < 0) + return ret; + } else { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } } + pdata = client->dev.platform_data; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -579,6 +587,7 @@ static int lp5562_remove(struct i2c_client *client) static const struct i2c_device_id lp5562_id[] = { { "lp5562", 0 }, + { "ti,lp5562", 0 }, /* OF compatible */ { } }; MODULE_DEVICE_TABLE(i2c, lp5562_id); -- cgit v0.10.2 From b548a34ba47c1fd73316493c0690c8bf3111ff9d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 May 2013 21:48:07 -0700 Subject: leds: lp5521: Properly setup of_device_id table Don't mix of_device_id entry in i2c_device_id table. Signed-off-by: Axel Lin Reviewed-by: Linus Walleij Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index d461e26..1392feb 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -490,14 +490,22 @@ static int lp5521_remove(struct i2c_client *client) static const struct i2c_device_id lp5521_id[] = { { "lp5521", 0 }, /* Three channel chip */ - { "national,lp5521", 0 }, /* OF compatible */ { } }; MODULE_DEVICE_TABLE(i2c, lp5521_id); +#ifdef CONFIG_OF +static const struct of_device_id of_lp5521_leds_match[] = { + { .compatible = "national,lp5521", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_lp5521_leds_match); +#endif static struct i2c_driver lp5521_driver = { .driver = { .name = "lp5521", + .of_match_table = of_match_ptr(of_lp5521_leds_match), }, .probe = lp5521_probe, .remove = lp5521_remove, -- cgit v0.10.2 From 33c88b67f3b66d3a7203862d520b1d07ee0cecb6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 May 2013 21:48:57 -0700 Subject: leds: lp5523: Properly setup of_device_id table Don't mix of_device_id entry in i2c_device_id table. Signed-off-by: Axel Lin Reviewed-by: Linus Walleij Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 365e914..3979428 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -503,15 +503,24 @@ static int lp5523_remove(struct i2c_client *client) static const struct i2c_device_id lp5523_id[] = { { "lp5523", LP5523 }, { "lp55231", LP55231 }, - { "national,lp5523", 0 }, /* OF compatible */ { } }; MODULE_DEVICE_TABLE(i2c, lp5523_id); +#ifdef CONFIG_OF +static const struct of_device_id of_lp5523_leds_match[] = { + { .compatible = "national,lp5523", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_lp5523_leds_match); +#endif + static struct i2c_driver lp5523_driver = { .driver = { .name = "lp5523x", + .of_match_table = of_match_ptr(of_lp5523_leds_match), }, .probe = lp5523_probe, .remove = lp5523_remove, -- cgit v0.10.2 From 28720cff9feeb705a39f54c196bc529fb33d1542 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 May 2013 21:49:37 -0700 Subject: leds: lp5562: Properly setup of_device_id table Don't mix of_device_id entry in i2c_device_id table. Signed-off-by: Axel Lin Reviewed-by: Linus Walleij Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index e53bcb8..cbd856d 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -587,14 +587,23 @@ static int lp5562_remove(struct i2c_client *client) static const struct i2c_device_id lp5562_id[] = { { "lp5562", 0 }, - { "ti,lp5562", 0 }, /* OF compatible */ { } }; MODULE_DEVICE_TABLE(i2c, lp5562_id); +#ifdef CONFIG_OF +static const struct of_device_id of_lp5562_leds_match[] = { + { .compatible = "ti,lp5562", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_lp5562_leds_match); +#endif + static struct i2c_driver lp5562_driver = { .driver = { .name = "lp5562", + .of_match_table = of_match_ptr(of_lp5562_leds_match), }, .probe = lp5562_probe, .remove = lp5562_remove, -- cgit v0.10.2 From bfa855bad39b7a266c00efdd2dc5887bcd41bb70 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 20 May 2013 08:23:45 -0700 Subject: leds: leds-gpio: Let device core handle pinctrl Since commit ab78029 (drivers/pinctrl: grab default handles from device core) we can rely on device core for handling pinctrl, so remove devm_pinctrl_get_select_default() from the driver. Reported-by: Stephen Warren Signed-off-by: Fabio Estevam Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 02c4cc1..84d74c37 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -20,7 +20,6 @@ #include #include #include -#include #include struct gpio_led_data { @@ -236,13 +235,8 @@ static int gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_leds_priv *priv; - struct pinctrl *pinctrl; int i, ret = 0; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, - "pins are not configured from the driver\n"); if (pdata && pdata->num_leds) { priv = devm_kzalloc(&pdev->dev, -- cgit v0.10.2 From 84196a2ffbac42f1649cc6e193be6016b233d312 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 23 May 2013 03:28:33 -0700 Subject: leds: use platform_{get,set}_drvdata() Use the wrapper functions for getting and setting the driver data using platform_device instead of using dev_{get,set}_drvdata() with &pdev->dev, so we can directly pass a struct platform_device. Signed-off-by: Jingoo Han Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index f5b9ea3..232b3ce 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -204,7 +204,7 @@ static int pm860x_led_probe(struct platform_device *pdev) sprintf(data->name, "led1-blue"); break; } - dev_set_drvdata(&pdev->dev, data); + platform_set_drvdata(pdev, data); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->port = pdev->id; diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index 8979299..388632d 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c @@ -159,14 +159,14 @@ static int sunfire_led_generic_probe(struct platform_device *pdev, } } - dev_set_drvdata(&pdev->dev, p); + platform_set_drvdata(pdev, p); return 0; } static int sunfire_led_generic_remove(struct platform_device *pdev) { - struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev); + struct sunfire_drvdata *p = platform_get_drvdata(pdev); int i; for (i = 0; i < NUM_LEDS_PER_BOARD; i++) diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index 6bd5c67..120815a 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -241,7 +241,7 @@ static int wm831x_status_probe(struct platform_device *pdev) GFP_KERNEL); if (!drvdata) return -ENOMEM; - dev_set_drvdata(&pdev->dev, drvdata); + platform_set_drvdata(pdev, drvdata); drvdata->wm831x = wm831x; drvdata->reg = res->start; -- cgit v0.10.2 From fb277f5b3a15c895586545d3938dc869e760bec6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 31 May 2013 05:55:04 -0700 Subject: leds: renesas-tpu: cleanup a small type issue Static checkers complain that, although this is declared as an unsigned long, we can only use the lower 32 bits. For anything higher, we hit bugs widening then bitwise negate or wrapping bugs doing the left shift. From looking at the context, this is not a problem because we only use 16 bits. I've changed some types to make it more clear. Signed-off-by: Dan Carpenter Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c index 9483f1c..adebf49 100644 --- a/drivers/leds/leds-renesas-tpu.c +++ b/drivers/leds/leds-renesas-tpu.c @@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(r_tpu_lock); #define TGRC 8 /* Timer general register C (+0x20) */ #define TGRD 9 /* Timer general register D (+0x24) */ -static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr) +static inline u16 r_tpu_read(struct r_tpu_priv *p, int reg_nr) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; @@ -75,8 +75,7 @@ static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr) return ioread16(base + offs); } -static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, - unsigned short value) +static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, u16 value) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; @@ -93,7 +92,8 @@ static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; - unsigned long flags, value; + unsigned long flags; + u16 value; /* start stop register shared by multiple timer channels */ spin_lock_irqsave(&r_tpu_lock, flags); -- cgit v0.10.2 From 9d263813c27e2ad3da7ea0877e623f4ff8767ddd Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Jun 2013 09:59:30 -0700 Subject: leds: leds-mc13783: Prepare driver to support MC13892 LEDs This patch rewrite driver code to be ready to add support for MC13892 LEDs and probe from devicetree. (cooloney@gmail.com: fix one coding style issue when apply this patch) Signed-off-by: Alexander Shiyan Tested-by: Philippe Retornaz Signed-off-by: Bryan Wu diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index dae4cd7..6f424ec 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -268,10 +268,11 @@ static struct mc13xxx_led_platform_data moboard_led[] = { static struct mc13xxx_leds_platform_data moboard_leds = { .num_leds = ARRAY_SIZE(moboard_led), .led = moboard_led, - .flags = MC13783_LED_SLEWLIMTC, - .abmode = MC13783_LED_AB_DISABLED, - .tc1_period = MC13783_LED_PERIOD_10MS, - .tc2_period = MC13783_LED_PERIOD_10MS, + .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0), + .led_control[1] = MC13783_LED_C1_SLEWLIM, + .led_control[2] = MC13783_LED_C2_SLEWLIM, + .led_control[3] = MC13783_LED_C3_PERIOD(0), + .led_control[4] = MC13783_LED_C3_PERIOD(0), }; static struct mc13xxx_buttons_platform_data moboard_buttons = { diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index ea8fc5d..da8ec24 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -22,9 +22,16 @@ #include #include #include -#include -struct mc13783_led { +#define MC13XXX_REG_LED_CONTROL(x) (51 + (x)) + +struct mc13xxx_led_devtype { + int led_min; + int led_max; + int num_regs; +}; + +struct mc13xxx_led { struct led_classdev cdev; struct work_struct work; struct mc13xxx *master; @@ -32,66 +39,35 @@ struct mc13783_led { int id; }; -#define MC13783_REG_LED_CONTROL_0 51 -#define MC13783_LED_C0_ENABLE_BIT (1 << 0) -#define MC13783_LED_C0_TRIODE_MD_BIT (1 << 7) -#define MC13783_LED_C0_TRIODE_AD_BIT (1 << 8) -#define MC13783_LED_C0_TRIODE_KP_BIT (1 << 9) -#define MC13783_LED_C0_BOOST_BIT (1 << 10) -#define MC13783_LED_C0_ABMODE_MASK 0x7 -#define MC13783_LED_C0_ABMODE 11 -#define MC13783_LED_C0_ABREF_MASK 0x3 -#define MC13783_LED_C0_ABREF 14 - -#define MC13783_REG_LED_CONTROL_1 52 -#define MC13783_LED_C1_TC1HALF_BIT (1 << 18) - -#define MC13783_REG_LED_CONTROL_2 53 -#define MC13783_LED_C2_BL_P_MASK 0xf -#define MC13783_LED_C2_MD_P 9 -#define MC13783_LED_C2_AD_P 13 -#define MC13783_LED_C2_KP_P 17 -#define MC13783_LED_C2_BL_C_MASK 0x7 -#define MC13783_LED_C2_MD_C 0 -#define MC13783_LED_C2_AD_C 3 -#define MC13783_LED_C2_KP_C 6 - -#define MC13783_REG_LED_CONTROL_3 54 -#define MC13783_LED_C3_TC_P 6 -#define MC13783_LED_C3_TC_P_MASK 0x1f - -#define MC13783_REG_LED_CONTROL_4 55 -#define MC13783_REG_LED_CONTROL_5 56 - -#define MC13783_LED_Cx_PERIOD 21 -#define MC13783_LED_Cx_PERIOD_MASK 0x3 -#define MC13783_LED_Cx_SLEWLIM_BIT (1 << 23) -#define MC13783_LED_Cx_TRIODE_TC_BIT (1 << 23) -#define MC13783_LED_Cx_TC_C_MASK 0x3 - -static void mc13783_led_work(struct work_struct *work) +struct mc13xxx_leds { + struct mc13xxx_led_devtype *devtype; + int num_leds; + struct mc13xxx_led led[0]; +}; + +static void mc13xxx_led_work(struct work_struct *work) { - struct mc13783_led *led = container_of(work, struct mc13783_led, work); - int reg = 0; - int mask = 0; - int value = 0; - int bank, off, shift; + struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work); + int reg, mask, value, bank, off, shift; switch (led->id) { case MC13783_LED_MD: - reg = MC13783_REG_LED_CONTROL_2; - mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P; - value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 9; + mask = 0x0f; + value = led->new_brightness >> 4; break; case MC13783_LED_AD: - reg = MC13783_REG_LED_CONTROL_2; - mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P; - value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 13; + mask = 0x0f; + value = led->new_brightness >> 4; break; case MC13783_LED_KP: - reg = MC13783_REG_LED_CONTROL_2; - mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P; - value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 17; + mask = 0x0f; + value = led->new_brightness >> 4; break; case MC13783_LED_R1: case MC13783_LED_G1: @@ -103,57 +79,50 @@ static void mc13783_led_work(struct work_struct *work) case MC13783_LED_G3: case MC13783_LED_B3: off = led->id - MC13783_LED_R1; - bank = off/3; - reg = MC13783_REG_LED_CONTROL_3 + off/3; - shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P; - value = (led->new_brightness >> 3) << shift; - mask = MC13783_LED_C3_TC_P_MASK << shift; + bank = off / 3; + reg = MC13XXX_REG_LED_CONTROL(3) + bank; + shift = (off - bank * 3) * 5 + 6; + value = led->new_brightness >> 3; + mask = 0x1f; break; + default: + BUG(); } mc13xxx_lock(led->master); - - mc13xxx_reg_rmw(led->master, reg, mask, value); - + mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); mc13xxx_unlock(led->master); } -static void mc13783_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static void mc13xxx_led_set(struct led_classdev *led_cdev, + enum led_brightness value) { - struct mc13783_led *led; + struct mc13xxx_led *led = + container_of(led_cdev, struct mc13xxx_led, cdev); - led = container_of(led_cdev, struct mc13783_led, cdev); led->new_brightness = value; schedule_work(&led->work); } -static int mc13783_led_setup(struct mc13783_led *led, int max_current) +static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current) { - int shift = 0; - int mask = 0; - int value = 0; - int reg = 0; - int ret, bank; + int shift, mask, reg, ret, bank; switch (led->id) { case MC13783_LED_MD: - shift = MC13783_LED_C2_MD_C; - mask = MC13783_LED_C2_BL_C_MASK; - value = max_current & MC13783_LED_C2_BL_C_MASK; - reg = MC13783_REG_LED_CONTROL_2; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 0; + mask = 0x07; break; case MC13783_LED_AD: - shift = MC13783_LED_C2_AD_C; - mask = MC13783_LED_C2_BL_C_MASK; - value = max_current & MC13783_LED_C2_BL_C_MASK; - reg = MC13783_REG_LED_CONTROL_2; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 3; + mask = 0x07; break; case MC13783_LED_KP: - shift = MC13783_LED_C2_KP_C; - mask = MC13783_LED_C2_BL_C_MASK; - value = max_current & MC13783_LED_C2_BL_C_MASK; - reg = MC13783_REG_LED_CONTROL_2; + reg = MC13XXX_REG_LED_CONTROL(2); + shift = 6; + mask = 0x07; break; case MC13783_LED_R1: case MC13783_LED_G1: @@ -164,228 +133,165 @@ static int mc13783_led_setup(struct mc13783_led *led, int max_current) case MC13783_LED_R3: case MC13783_LED_G3: case MC13783_LED_B3: - bank = (led->id - MC13783_LED_R1)/3; - reg = MC13783_REG_LED_CONTROL_3 + bank; + bank = (led->id - MC13783_LED_R1) / 3; + reg = MC13XXX_REG_LED_CONTROL(3) + bank; shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2; - mask = MC13783_LED_Cx_TC_C_MASK; - value = max_current & MC13783_LED_Cx_TC_C_MASK; + mask = 0x03; break; + default: + BUG(); } mc13xxx_lock(led->master); - ret = mc13xxx_reg_rmw(led->master, reg, mask << shift, - value << shift); - + max_current << shift); mc13xxx_unlock(led->master); - return ret; -} - -static int mc13783_leds_prepare(struct platform_device *pdev) -{ - struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent); - int ret = 0; - int reg = 0; - - mc13xxx_lock(dev); - - if (pdata->flags & MC13783_LED_TC1HALF) - reg |= MC13783_LED_C1_TC1HALF_BIT; - - if (pdata->flags & MC13783_LED_SLEWLIMTC) - reg |= MC13783_LED_Cx_SLEWLIM_BIT; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg); - if (ret) - goto out; - - reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) << - MC13783_LED_Cx_PERIOD; - - if (pdata->flags & MC13783_LED_SLEWLIMBL) - reg |= MC13783_LED_Cx_SLEWLIM_BIT; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg); - if (ret) - goto out; - - reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) << - MC13783_LED_Cx_PERIOD; - - if (pdata->flags & MC13783_LED_TRIODE_TC1) - reg |= MC13783_LED_Cx_TRIODE_TC_BIT; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg); - if (ret) - goto out; - reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) << - MC13783_LED_Cx_PERIOD; - - if (pdata->flags & MC13783_LED_TRIODE_TC2) - reg |= MC13783_LED_Cx_TRIODE_TC_BIT; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg); - if (ret) - goto out; - - reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) << - MC13783_LED_Cx_PERIOD; - - if (pdata->flags & MC13783_LED_TRIODE_TC3) - reg |= MC13783_LED_Cx_TRIODE_TC_BIT; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg); - if (ret) - goto out; - - reg = MC13783_LED_C0_ENABLE_BIT; - if (pdata->flags & MC13783_LED_TRIODE_MD) - reg |= MC13783_LED_C0_TRIODE_MD_BIT; - if (pdata->flags & MC13783_LED_TRIODE_AD) - reg |= MC13783_LED_C0_TRIODE_AD_BIT; - if (pdata->flags & MC13783_LED_TRIODE_KP) - reg |= MC13783_LED_C0_TRIODE_KP_BIT; - if (pdata->flags & MC13783_LED_BOOST_EN) - reg |= MC13783_LED_C0_BOOST_BIT; - - reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) << - MC13783_LED_C0_ABMODE; - reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) << - MC13783_LED_C0_ABREF; - - ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg); - -out: - mc13xxx_unlock(dev); return ret; } -static int mc13783_led_probe(struct platform_device *pdev) +static int __init mc13xxx_led_probe(struct platform_device *pdev) { struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13xxx_led_platform_data *led_cur; - struct mc13783_led *led, *led_dat; - int ret, i; - int init_led = 0; - - if (pdata == NULL) { - dev_err(&pdev->dev, "missing platform data\n"); + struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_led_devtype *devtype = + (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; + struct mc13xxx_leds *leds; + int i, id, num_leds, ret; + u32 reg, init_led = 0; + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); return -ENODEV; } - if (pdata->num_leds < 1 || pdata->num_leds > (MC13783_LED_MAX + 1)) { - dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds); + num_leds = pdata->num_leds; + + if ((num_leds < 1) || + (num_leds > (devtype->led_max - devtype->led_min + 1))) { + dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds); return -EINVAL; } - led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led), - GFP_KERNEL); - if (led == NULL) { - dev_err(&pdev->dev, "failed to alloc memory\n"); + leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) + + sizeof(struct mc13xxx_leds), GFP_KERNEL); + if (!leds) return -ENOMEM; + + leds->devtype = devtype; + leds->num_leds = num_leds; + platform_set_drvdata(pdev, leds); + + mc13xxx_lock(mcdev); + for (i = 0; i < devtype->num_regs; i++) { + reg = pdata->led_control[i]; + WARN_ON(reg >= (1 << 24)); + ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); + if (ret) + break; } + mc13xxx_unlock(mcdev); - ret = mc13783_leds_prepare(pdev); if (ret) { - dev_err(&pdev->dev, "unable to init led driver\n"); + dev_err(&pdev->dev, "Unable to init LED driver\n"); return ret; } - for (i = 0; i < pdata->num_leds; i++) { - led_dat = &led[i]; - led_cur = &pdata->led[i]; + for (i = 0; i < num_leds; i++) { + const char *name, *trig; + char max_current; - if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) { - dev_err(&pdev->dev, "invalid id %d\n", led_cur->id); - ret = -EINVAL; - goto err_register; + ret = -EINVAL; + + id = pdata->led[i].id; + name = pdata->led[i].name; + trig = pdata->led[i].default_trigger; + max_current = pdata->led[i].max_current; + + if ((id > devtype->led_max) || (id < devtype->led_min)) { + dev_err(&pdev->dev, "Invalid ID %i\n", id); + break; } - if (init_led & (1 << led_cur->id)) { - dev_err(&pdev->dev, "led %d already initialized\n", - led_cur->id); - ret = -EINVAL; - goto err_register; + if (init_led & (1 << id)) { + dev_warn(&pdev->dev, + "LED %i already initialized\n", id); + break; } - init_led |= 1 << led_cur->id; - led_dat->cdev.name = led_cur->name; - led_dat->cdev.default_trigger = led_cur->default_trigger; - led_dat->cdev.brightness_set = mc13783_led_set; - led_dat->cdev.brightness = LED_OFF; - led_dat->id = led_cur->id; - led_dat->master = dev_get_drvdata(pdev->dev.parent); + init_led |= 1 << id; + leds->led[i].id = id; + leds->led[i].master = mcdev; + leds->led[i].cdev.name = name; + leds->led[i].cdev.default_trigger = trig; + leds->led[i].cdev.brightness_set = mc13xxx_led_set; + leds->led[i].cdev.brightness = LED_OFF; - INIT_WORK(&led_dat->work, mc13783_led_work); + INIT_WORK(&leds->led[i].work, mc13xxx_led_work); - ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev); + ret = mc13xxx_led_setup(&leds->led[i], max_current); if (ret) { - dev_err(&pdev->dev, "failed to register led %d\n", - led_dat->id); - goto err_register; + dev_err(&pdev->dev, "Unable to setup LED %i\n", id); + break; } - - ret = mc13783_led_setup(led_dat, led_cur->max_current); + ret = led_classdev_register(pdev->dev.parent, + &leds->led[i].cdev); if (ret) { - dev_err(&pdev->dev, "unable to init led %d\n", - led_dat->id); - i++; - goto err_register; + dev_err(&pdev->dev, "Failed to register LED %i\n", id); + break; } } - platform_set_drvdata(pdev, led); - return 0; - -err_register: - for (i = i - 1; i >= 0; i--) { - led_classdev_unregister(&led[i].cdev); - cancel_work_sync(&led[i].work); - } + if (ret) + while (--i >= 0) { + led_classdev_unregister(&leds->led[i].cdev); + cancel_work_sync(&leds->led[i].work); + } return ret; } -static int mc13783_led_remove(struct platform_device *pdev) +static int mc13xxx_led_remove(struct platform_device *pdev) { - struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13783_led *led = platform_get_drvdata(pdev); - struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_leds *leds = platform_get_drvdata(pdev); int i; - for (i = 0; i < pdata->num_leds; i++) { - led_classdev_unregister(&led[i].cdev); - cancel_work_sync(&led[i].work); + for (i = 0; i < leds->num_leds; i++) { + led_classdev_unregister(&leds->led[i].cdev); + cancel_work_sync(&leds->led[i].work); } - mc13xxx_lock(dev); - - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0); - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0); - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0); - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0); - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0); - mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0); - - mc13xxx_unlock(dev); + mc13xxx_lock(mcdev); + for (i = 0; i < leds->devtype->num_regs; i++) + mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0); + mc13xxx_unlock(mcdev); return 0; } -static struct platform_driver mc13783_led_driver = { +static const struct mc13xxx_led_devtype mc13783_led_devtype = { + .led_min = MC13783_LED_MD, + .led_max = MC13783_LED_B3, + .num_regs = 6, +}; + +static const struct platform_device_id mc13xxx_led_id_table[] = { + { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); + +static struct platform_driver mc13xxx_led_driver = { .driver = { - .name = "mc13783-led", + .name = "mc13xxx-led", .owner = THIS_MODULE, }, - .probe = mc13783_led_probe, - .remove = mc13783_led_remove, + .remove = mc13xxx_led_remove, + .id_table = mc13xxx_led_id_table, }; +module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe); -module_platform_driver(mc13783_led_driver); - -MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC"); +MODULE_DESCRIPTION("LEDs driver for Freescale MC13XXX PMIC"); MODULE_AUTHOR("Philippe Retornaz "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mc13783-led"); diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index bf07075..ee280f1 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -78,20 +78,23 @@ struct mc13xxx_regulator_platform_data { struct mc13xxx_regulator_init_data *regulators; }; +enum { + /* MC13783 LED IDs */ + MC13783_LED_MD, + MC13783_LED_AD, + MC13783_LED_KP, + MC13783_LED_R1, + MC13783_LED_G1, + MC13783_LED_B1, + MC13783_LED_R2, + MC13783_LED_G2, + MC13783_LED_B2, + MC13783_LED_R3, + MC13783_LED_G3, + MC13783_LED_B3, +}; + struct mc13xxx_led_platform_data { -#define MC13783_LED_MD 0 -#define MC13783_LED_AD 1 -#define MC13783_LED_KP 2 -#define MC13783_LED_R1 3 -#define MC13783_LED_G1 4 -#define MC13783_LED_B1 5 -#define MC13783_LED_R2 6 -#define MC13783_LED_G2 7 -#define MC13783_LED_B2 8 -#define MC13783_LED_R3 9 -#define MC13783_LED_G3 10 -#define MC13783_LED_B3 11 -#define MC13783_LED_MAX MC13783_LED_B3 int id; const char *name; const char *default_trigger; @@ -100,46 +103,36 @@ struct mc13xxx_led_platform_data { char max_current; }; +#define MAX_LED_CONTROL_REGS 6 + struct mc13xxx_leds_platform_data { - int num_leds; struct mc13xxx_led_platform_data *led; + int num_leds; -#define MC13783_LED_TRIODE_MD (1 << 0) -#define MC13783_LED_TRIODE_AD (1 << 1) -#define MC13783_LED_TRIODE_KP (1 << 2) -#define MC13783_LED_BOOST_EN (1 << 3) -#define MC13783_LED_TC1HALF (1 << 4) -#define MC13783_LED_SLEWLIMTC (1 << 5) -#define MC13783_LED_SLEWLIMBL (1 << 6) -#define MC13783_LED_TRIODE_TC1 (1 << 7) -#define MC13783_LED_TRIODE_TC2 (1 << 8) -#define MC13783_LED_TRIODE_TC3 (1 << 9) - int flags; - -#define MC13783_LED_AB_DISABLED 0 -#define MC13783_LED_AB_MD1 1 -#define MC13783_LED_AB_MD12 2 -#define MC13783_LED_AB_MD123 3 -#define MC13783_LED_AB_MD1234 4 -#define MC13783_LED_AB_MD1234_AD1 5 -#define MC13783_LED_AB_MD1234_AD12 6 -#define MC13783_LED_AB_MD1_AD 7 - char abmode; - -#define MC13783_LED_ABREF_200MV 0 -#define MC13783_LED_ABREF_400MV 1 -#define MC13783_LED_ABREF_600MV 2 -#define MC13783_LED_ABREF_800MV 3 - char abref; - -#define MC13783_LED_PERIOD_10MS 0 -#define MC13783_LED_PERIOD_100MS 1 -#define MC13783_LED_PERIOD_500MS 2 -#define MC13783_LED_PERIOD_2S 3 - char bl_period; - char tc1_period; - char tc2_period; - char tc3_period; +/* LED Control 0 */ +#define MC13783_LED_C0_ENABLE (1 << 0) +#define MC13783_LED_C0_TRIODE_MD (1 << 7) +#define MC13783_LED_C0_TRIODE_AD (1 << 8) +#define MC13783_LED_C0_TRIODE_KP (1 << 9) +#define MC13783_LED_C0_BOOST (1 << 10) +#define MC13783_LED_C0_ABMODE(x) (((x) & 0x7) << 11) +#define MC13783_LED_C0_ABREF(x) (((x) & 0x3) << 14) +/* LED Control 1 */ +#define MC13783_LED_C1_TC1HALF (1 << 18) +#define MC13783_LED_C1_SLEWLIM (1 << 23) +/* LED Control 2 */ +#define MC13783_LED_C2_PERIOD(x) (((x) & 0x3) << 21) +#define MC13783_LED_C2_SLEWLIM (1 << 23) +/* LED Control 3 */ +#define MC13783_LED_C3_PERIOD(x) (((x) & 0x3) << 21) +#define MC13783_LED_C3_TRIODE_TC1 (1 << 23) +/* LED Control 4 */ +#define MC13783_LED_C4_PERIOD(x) (((x) & 0x3) << 21) +#define MC13783_LED_C4_TRIODE_TC2 (1 << 23) +/* LED Control 5 */ +#define MC13783_LED_C5_PERIOD(x) (((x) & 0x3) << 21) +#define MC13783_LED_C5_TRIODE_TC3 (1 << 23) + u32 led_control[MAX_LED_CONTROL_REGS]; }; struct mc13xxx_buttons_platform_data { -- cgit v0.10.2 From ae6cdb03ef1d352c489d6c86e0bcec51365a2c64 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 10 Jun 2013 09:59:31 -0700 Subject: leds: leds-mc13783: Add MC13892 LED support Signed-off-by: Alexander Shiyan Tested-by: Philippe Retornaz Signed-off-by: Bryan Wu diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ef99229..e43402d 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -388,12 +388,12 @@ config LEDS_DELL_NETBOOKS notebooks that have an external LED. config LEDS_MC13783 - tristate "LED Support for MC13783 PMIC" + tristate "LED Support for MC13XXX PMIC" depends on LEDS_CLASS - depends on MFD_MC13783 + depends on MFD_MC13XXX help This option enable support for on-chip LED drivers found - on Freescale Semiconductor MC13783 PMIC. + on Freescale Semiconductor MC13783/MC13892 PMIC. config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index da8ec24..f4de980 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -1,5 +1,5 @@ /* - * LEDs driver for Freescale MC13783 + * LEDs driver for Freescale MC13783/MC13892 * * Copyright (C) 2010 Philippe Rétornaz * @@ -85,6 +85,34 @@ static void mc13xxx_led_work(struct work_struct *work) value = led->new_brightness >> 3; mask = 0x1f; break; + case MC13892_LED_MD: + reg = MC13XXX_REG_LED_CONTROL(0); + shift = 3; + mask = 0x3f; + value = led->new_brightness >> 2; + break; + case MC13892_LED_AD: + reg = MC13XXX_REG_LED_CONTROL(0); + shift = 15; + mask = 0x3f; + value = led->new_brightness >> 2; + break; + case MC13892_LED_KP: + reg = MC13XXX_REG_LED_CONTROL(1); + shift = 3; + mask = 0x3f; + value = led->new_brightness >> 2; + break; + case MC13892_LED_R: + case MC13892_LED_G: + case MC13892_LED_B: + off = led->id - MC13892_LED_R; + bank = off / 2; + reg = MC13XXX_REG_LED_CONTROL(2) + bank; + shift = (off - bank * 2) * 12 + 3; + value = led->new_brightness >> 2; + mask = 0x3f; + break; default: BUG(); } @@ -138,6 +166,29 @@ static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current) shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2; mask = 0x03; break; + case MC13892_LED_MD: + reg = MC13XXX_REG_LED_CONTROL(0); + shift = 9; + mask = 0x07; + break; + case MC13892_LED_AD: + reg = MC13XXX_REG_LED_CONTROL(0); + shift = 21; + mask = 0x07; + break; + case MC13892_LED_KP: + reg = MC13XXX_REG_LED_CONTROL(1); + shift = 9; + mask = 0x07; + break; + case MC13892_LED_R: + case MC13892_LED_G: + case MC13892_LED_B: + bank = (led->id - MC13892_LED_R) / 2; + reg = MC13XXX_REG_LED_CONTROL(2) + bank; + shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9; + mask = 0x07; + break; default: BUG(); } @@ -276,8 +327,15 @@ static const struct mc13xxx_led_devtype mc13783_led_devtype = { .num_regs = 6, }; +static const struct mc13xxx_led_devtype mc13892_led_devtype = { + .led_min = MC13892_LED_MD, + .led_max = MC13892_LED_B, + .num_regs = 4, +}; + static const struct platform_device_id mc13xxx_led_id_table[] = { { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, + { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, }, { } }; MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index ee280f1..41ed592 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -92,6 +92,13 @@ enum { MC13783_LED_R3, MC13783_LED_G3, MC13783_LED_B3, + /* MC13892 LED IDs */ + MC13892_LED_MD, + MC13892_LED_AD, + MC13892_LED_KP, + MC13892_LED_R, + MC13892_LED_G, + MC13892_LED_B, }; struct mc13xxx_led_platform_data { -- cgit v0.10.2 From 73e1ab41a80d36207e8ea7cc2c9897afdeeef387 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 20 Jun 2013 12:08:44 -0700 Subject: leds: Convert led class driver from legacy pm ops to dev_pm_ops Convert drivers/leds/led-class to use dev_pm_ops for power management and remove Legacy PM ops hooks. With this change, led class registers suspend/resume callbacks via class->pm (dev_pm_ops) instead of Legacy class->suspend/resume. When __device_suspend() runs call-backs, it will find class->pm ops for the led class. Signed-off-by: Shuah Khan Signed-off-by: Bryan Wu diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index a20752f..4336e37 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -156,7 +156,7 @@ void led_classdev_resume(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_resume); -static int led_suspend(struct device *dev, pm_message_t state) +static int led_suspend(struct device *dev) { struct led_classdev *led_cdev = dev_get_drvdata(dev); @@ -176,6 +176,11 @@ static int led_resume(struct device *dev) return 0; } +static const struct dev_pm_ops leds_class_dev_pm_ops = { + .suspend = led_suspend, + .resume = led_resume, +}; + /** * led_classdev_register - register a new object of led_classdev class. * @parent: The device to register. @@ -252,8 +257,7 @@ static int __init leds_init(void) leds_class = class_create(THIS_MODULE, "leds"); if (IS_ERR(leds_class)) return PTR_ERR(leds_class); - leds_class->suspend = led_suspend; - leds_class->resume = led_resume; + leds_class->pm = &leds_class_dev_pm_ops; leds_class->dev_attrs = led_class_attrs; return 0; } -- cgit v0.10.2 From cf3b1c2ba362ecea5b8e07d370233e25f3d6366d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 2 Jul 2013 08:17:17 -0700 Subject: leds: mc13783: Fix "uninitialized variable" warning drivers/leds/leds-mc13783.c: In function 'mc13xxx_led_probe': drivers/leds/leds-mc13783.c:195:2: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] Signed-off-by: Alexander Shiyan Signed-off-by: Bryan Wu diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index f4de980..fa9b439 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -208,7 +208,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) struct mc13xxx_led_devtype *devtype = (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; struct mc13xxx_leds *leds; - int i, id, num_leds, ret; + int i, id, num_leds, ret = -ENODATA; u32 reg, init_led = 0; if (!pdata) { -- cgit v0.10.2