diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:55:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:55:33 -0700 |
commit | c16bfeb264decb964742067f02fdd51494e25e64 (patch) | |
tree | 255eac59926c0d08168581b7c324612694dffe5b | |
parent | 1286da8bc009cb2aee7f285e94623fc974c0c983 (diff) | |
parent | cf3b1c2ba362ecea5b8e07d370233e25f3d6366d (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds
Pull LED subsystem updates from Bryan Wu:
- lp55xx device tree updates
- mc13xxx driver updates
- some clean up
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
leds: mc13783: Fix "uninitialized variable" warning
leds: Convert led class driver from legacy pm ops to dev_pm_ops
leds: leds-mc13783: Add MC13892 LED support
leds: leds-mc13783: Prepare driver to support MC13892 LEDs
leds: renesas-tpu: cleanup a small type issue
leds: use platform_{get,set}_drvdata()
leds: leds-gpio: Let device core handle pinctrl
leds: lp5562: Properly setup of_device_id table
leds: lp5523: Properly setup of_device_id table
leds: lp5521: Properly setup of_device_id table
leds: lp5562: support the device tree feature
leds: lp55xx: support dynamic channel settings in the device tree structure
leds: leds-ns2: remove unnecessary platform_set_drvdata()
leds: leds-mc13783: remove unnecessary platform_set_drvdata()
leds: leds-gpio: remove unnecessary platform_set_drvdata()
leds: atmel-pwm: remove unnecessary platform_set_drvdata()
leds: lp55xx: add support for Device Tree bindings
-rw-r--r-- | Documentation/devicetree/bindings/leds/leds-lp55xx.txt | 147 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-mx31moboard.c | 9 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 6 | ||||
-rw-r--r-- | drivers/leds/led-class.c | 10 | ||||
-rw-r--r-- | drivers/leds/leds-88pm860x.c | 2 | ||||
-rw-r--r-- | drivers/leds/leds-atmel-pwm.c | 1 | ||||
-rw-r--r-- | drivers/leds/leds-gpio.c | 8 | ||||
-rw-r--r-- | drivers/leds/leds-lp5521.c | 28 | ||||
-rw-r--r-- | drivers/leds/leds-lp5523.c | 28 | ||||
-rw-r--r-- | drivers/leds/leds-lp5562.c | 28 | ||||
-rw-r--r-- | drivers/leds/leds-lp55xx-common.c | 45 | ||||
-rw-r--r-- | drivers/leds/leds-lp55xx-common.h | 4 | ||||
-rw-r--r-- | drivers/leds/leds-mc13783.c | 467 | ||||
-rw-r--r-- | drivers/leds/leds-ns2.c | 2 | ||||
-rw-r--r-- | drivers/leds/leds-renesas-tpu.c | 8 | ||||
-rw-r--r-- | drivers/leds/leds-sunfire.c | 4 | ||||
-rw-r--r-- | drivers/leds/leds-wm831x-status.c | 2 | ||||
-rw-r--r-- | include/linux/mfd/mc13xxx.h | 100 |
18 files changed, 553 insertions, 346 deletions
diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt new file mode 100644 index 00000000000..d5176882d8b --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt @@ -0,0 +1,147 @@ +Binding for TI/National Semiconductor LP55xx Led Drivers + +Required properties: +- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" +- 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. + +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"; + 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>; + }; +}; + +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/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index dae4cd7be04..6f424eced18 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/Kconfig b/drivers/leds/Kconfig index ef992293598..e43402dd1de 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/led-class.c b/drivers/leds/led-class.c index a20752f562b..4336e37a97f 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; } diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index f5b9ea31579..232b3ce902e 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-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c index 8a39c5b20f7..90518f84b9c 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; } diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index b02b679abf3..84d74c373ca 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -20,7 +20,6 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/module.h> -#include <linux/pinctrl/consumer.h> #include <linux/err.h> 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, @@ -282,8 +276,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; } diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 19752c928aa..1392feb1bcf 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -31,6 +31,7 @@ #include <linux/mutex.h> #include <linux/platform_data/leds-lp55xx.h> #include <linux/slab.h> +#include <linux/of.h> #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) @@ -485,9 +494,18 @@ static const struct i2c_device_id lp5521_id[] = { }; 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, diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 229f734040a..3979428f310 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) @@ -500,9 +508,19 @@ static const struct i2c_device_id lp5523_id[] = { 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, diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 513f2390ca2..cbd856dac15 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) @@ -583,9 +591,19 @@ static const struct i2c_device_id lp5562_id[] = { }; 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, diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index ba34199dc3d..c2fecd4d391 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -19,6 +19,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/platform_data/leds-lp55xx.h> +#include <linux/slab.h> #include "leds-lp55xx-common.h" @@ -554,6 +555,50 @@ 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 device_node *child; + struct lp55xx_platform_data *pdata; + struct lp55xx_led_config *cfg; + int num_channels; + int i = 0; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + num_channels = of_get_child_count(np); + if (num_channels == 0) { + dev_err(dev, "no LED channels\n"); + return -EINVAL; + } + + cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + 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++; + } + + of_property_read_string(np, "label", &pdata->label); + of_property_read_u8(np, "clock-mode", &pdata->clock_mode); + + dev->platform_data = pdata; + + return 0; +} +EXPORT_SYMBOL_GPL(lp55xx_of_populate_pdata); + MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>"); 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 fa6a078bf54..dbbf86df0f1 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 */ diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index e942adaa750..fa9b439323b 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 * @@ -22,9 +22,16 @@ #include <linux/leds.h> #include <linux/workqueue.h> #include <linux/mfd/mc13xxx.h> -#include <linux/slab.h> -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,78 @@ 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; + 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(); } 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,229 +161,195 @@ 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; + 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(); } 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 = -ENODATA; + 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; + + ret = -EINVAL; - 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; |