summaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorDmitry Torokhov2013-03-18 03:40:50 +0100
committerDmitry Torokhov2013-03-18 03:40:50 +0100
commit688d794c4c3f8b08c814381ee2edd3ede5856056 (patch)
treeef680add71e2a9588d07d8b594edbc1b5cd127d7 /drivers/leds
parentUSB: cdc-acm - blacklist IMS PCU device (diff)
parentLinux 3.9-rc3 (diff)
downloadkernel-qcow2-linux-688d794c4c3f8b08c814381ee2edd3ede5856056.tar.gz
kernel-qcow2-linux-688d794c4c3f8b08c814381ee2edd3ede5856056.tar.xz
kernel-qcow2-linux-688d794c4c3f8b08c814381ee2edd3ede5856056.zip
Merge tag 'v3.9-rc3' into next
Merge with mainline to bring in module_platform_driver_probe() and devm_ioremap_resource().
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig18
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c2
-rw-r--r--drivers/leds/led-triggers.c25
-rw-r--r--drivers/leds/leds-88pm860x.c14
-rw-r--r--drivers/leds/leds-adp5520.c12
-rw-r--r--drivers/leds/leds-asic3.c6
-rw-r--r--drivers/leds/leds-atmel-pwm.c2
-rw-r--r--drivers/leds/leds-bd2802.c12
-rw-r--r--drivers/leds/leds-blinkm.c6
-rw-r--r--drivers/leds/leds-clevo-mail.c13
-rw-r--r--drivers/leds/leds-cobalt-qube.c17
-rw-r--r--drivers/leds/leds-cobalt-raq.c17
-rw-r--r--drivers/leds/leds-da903x.c16
-rw-r--r--drivers/leds/leds-da9052.c6
-rw-r--r--drivers/leds/leds-fsg.c15
-rw-r--r--drivers/leds/leds-gpio.c50
-rw-r--r--drivers/leds/leds-lm3530.c64
-rw-r--r--drivers/leds/leds-lm3533.c8
-rw-r--r--drivers/leds/leds-lm355x.c14
-rw-r--r--drivers/leds/leds-lm3642.c24
-rw-r--r--drivers/leds/leds-lp3944.c8
-rw-r--r--drivers/leds/leds-lp5521.c941
-rw-r--r--drivers/leds/leds-lp5523.c1060
-rw-r--r--drivers/leds/leds-lp55xx-common.c523
-rw-r--r--drivers/leds/leds-lp55xx-common.h134
-rw-r--r--drivers/leds/leds-lp8788.c15
-rw-r--r--drivers/leds/leds-lt3593.c28
-rw-r--r--drivers/leds/leds-max8997.c6
-rw-r--r--drivers/leds/leds-mc13783.c10
-rw-r--r--drivers/leds/leds-net48xx.c2
-rw-r--r--drivers/leds/leds-netxbig.c12
-rw-r--r--drivers/leds/leds-ns2.c122
-rw-r--r--drivers/leds/leds-ot200.c6
-rw-r--r--drivers/leds/leds-pca9532.c6
-rw-r--r--drivers/leds/leds-pca955x.c8
-rw-r--r--drivers/leds/leds-pca9633.c6
-rw-r--r--drivers/leds/leds-pwm.c158
-rw-r--r--drivers/leds/leds-rb532.c8
-rw-r--r--drivers/leds/leds-regulator.c6
-rw-r--r--drivers/leds/leds-renesas-tpu.c43
-rw-r--r--drivers/leds/leds-ss4200.c9
-rw-r--r--drivers/leds/leds-sunfire.c31
-rw-r--r--drivers/leds/leds-tca6507.c78
-rw-r--r--drivers/leds/leds-wm831x-status.c2
-rw-r--r--drivers/leds/leds-wm8350.c4
-rw-r--r--drivers/leds/leds-wrap.c2
-rw-r--r--drivers/leds/ledtrig-backlight.c4
-rw-r--r--drivers/leds/ledtrig-cpu.c21
-rw-r--r--drivers/leds/ledtrig-gpio.c2
50 files changed, 1755 insertions, 1842 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f508defc0d96..ec50824c02ec 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -154,7 +154,7 @@ config LEDS_HP6XX
config LEDS_PCA9532
tristate "LED driver for PCA9532 dimmer"
depends on LEDS_CLASS
- depends on I2C && INPUT && EXPERIMENTAL
+ depends on I2C && INPUT
help
This option enables support for NXP pca9532
LED controller. It is generally only useful
@@ -193,9 +193,18 @@ config LEDS_LP3944
To compile this driver as a module, choose M here: the
module will be called leds-lp3944.
+config LEDS_LP55XX_COMMON
+ tristate "Common Driver for TI/National LP5521 and LP5523/55231"
+ depends on LEDS_LP5521 || LEDS_LP5523
+ select FW_LOADER
+ help
+ This option supports common operations for LP5521 and LP5523/55231
+ devices.
+
config LEDS_LP5521
tristate "LED Support for N.S. LP5521 LED driver chip"
depends on LEDS_CLASS && I2C
+ select LEDS_LP55XX_COMMON
help
If you say yes here you get support for the National Semiconductor
LP5521 LED driver. It is 3 channel chip with programmable engines.
@@ -205,6 +214,7 @@ config LEDS_LP5521
config LEDS_LP5523
tristate "LED Support for TI/National LP5523/55231 LED driver chip"
depends on LEDS_CLASS && I2C
+ select LEDS_LP55XX_COMMON
help
If you say yes here you get support for TI/National Semiconductor
LP5523/55231 LED driver.
@@ -310,7 +320,7 @@ config LEDS_DAC124S085
config LEDS_PWM
tristate "PWM driven LED Support"
depends on LEDS_CLASS
- depends on HAVE_PWM
+ depends on PWM
help
This option enables support for pwm driven LEDs
@@ -379,7 +389,9 @@ config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs"
depends on LEDS_CLASS
depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || \
- MACH_NETSPACE_MAX_V2 || MACH_D2NET_V2
+ MACH_NETSPACE_MAX_V2 || MACH_D2NET_V2 || \
+ MACH_NETSPACE_V2_DT || MACH_INETSPACE_V2_DT || \
+ MACH_NETSPACE_MAX_V2_DT || MACH_NETSPACE_MINI_V2_DT
default y
help
This option enable support for the dual-GPIO LED found on the
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3fb9641b6194..215e7e3b6173 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
+obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 48cce18e9d6d..a20752f562bc 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -211,7 +211,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
led_trigger_set_default(led_cdev);
#endif
- printk(KERN_DEBUG "Registered led device: %s\n",
+ dev_dbg(parent, "Registered led device: %s\n",
led_cdev->name);
return 0;
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 262eb4193710..3c972b2f9893 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -166,6 +166,19 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_trigger_set_default);
+void led_trigger_rename_static(const char *name, struct led_trigger *trig)
+{
+ /* new name must be on a temporary string to prevent races */
+ BUG_ON(name == trig->name);
+
+ down_write(&triggers_list_lock);
+ /* this assumes that trig->name was originaly allocated to
+ * non constant storage */
+ strcpy((char *)trig->name, name);
+ up_write(&triggers_list_lock);
+}
+EXPORT_SYMBOL_GPL(led_trigger_rename_static);
+
/* LED Trigger Interface */
int led_trigger_register(struct led_trigger *trig)
@@ -300,13 +313,13 @@ void led_trigger_register_simple(const char *name, struct led_trigger **tp)
if (err < 0) {
kfree(trig);
trig = NULL;
- printk(KERN_WARNING "LED trigger %s failed to register"
- " (%d)\n", name, err);
+ pr_warn("LED trigger %s failed to register (%d)\n",
+ name, err);
}
- } else
- printk(KERN_WARNING "LED trigger %s failed to register"
- " (no memory)\n", name);
-
+ } else {
+ pr_warn("LED trigger %s failed to register (no memory)\n",
+ name);
+ }
*tp = trig;
}
EXPORT_SYMBOL_GPL(led_trigger_register_simple);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index b7e8cc0957fc..f5b9ea315790 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -128,8 +128,10 @@ static void pm860x_led_set(struct led_classdev *cdev,
static int pm860x_led_dt_init(struct platform_device *pdev,
struct pm860x_led *data)
{
- struct device_node *nproot = pdev->dev.parent->of_node, *np;
+ struct device_node *nproot, *np;
int iset = 0;
+
+ nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
nproot = of_find_node_by_name(nproot, "leds");
@@ -145,6 +147,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
break;
}
}
+ of_node_put(nproot);
return 0;
}
#else
@@ -165,15 +168,13 @@ static int pm860x_led_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "control");
if (!res) {
dev_err(&pdev->dev, "No REG resource for control\n");
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
data->reg_control = res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "blink");
if (!res) {
dev_err(&pdev->dev, "No REG resource for blink\n");
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
data->reg_blink = res->start;
memset(data->name, 0, MFD_NAME_SIZE);
@@ -224,9 +225,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
}
pm860x_led_set(&data->cdev, 0);
return 0;
-out:
- devm_kfree(&pdev->dev, data);
- return ret;
}
static int pm860x_led_remove(struct platform_device *pdev)
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
index aa56a867693a..e8072abe76e5 100644
--- a/drivers/leds/leds-adp5520.c
+++ b/drivers/leds/leds-adp5520.c
@@ -5,10 +5,10 @@
*
* Loosely derived from leds-da903x:
* Copyright (C) 2008 Compulab, Ltd.
- * Mike Rapoport <mike@compulab.co.il>
+ * Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
- * Eric Miao <eric.miao@marvell.com>
+ * Eric Miao <eric.miao@marvell.com>
*
* Licensed under the GPL-2 or later.
*/
@@ -85,7 +85,7 @@ static int adp5520_led_setup(struct adp5520_led *led)
return ret;
}
-static int __devinit adp5520_led_prepare(struct platform_device *pdev)
+static int adp5520_led_prepare(struct platform_device *pdev)
{
struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
struct device *dev = pdev->dev.parent;
@@ -101,7 +101,7 @@ static int __devinit adp5520_led_prepare(struct platform_device *pdev)
return ret;
}
-static int __devinit adp5520_led_probe(struct platform_device *pdev)
+static int adp5520_led_probe(struct platform_device *pdev)
{
struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
struct adp5520_led *led, *led_dat;
@@ -183,7 +183,7 @@ err:
return ret;
}
-static int __devexit adp5520_led_remove(struct platform_device *pdev)
+static int adp5520_led_remove(struct platform_device *pdev)
{
struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
struct adp5520_led *led;
@@ -208,7 +208,7 @@ static struct platform_driver adp5520_led_driver = {
.owner = THIS_MODULE,
},
.probe = adp5520_led_probe,
- .remove = __devexit_p(adp5520_led_remove),
+ .remove = adp5520_led_remove,
};
module_platform_driver(adp5520_led_driver);
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
index 5de74ff90dcf..b474745e001b 100644
--- a/drivers/leds/leds-asic3.c
+++ b/drivers/leds/leds-asic3.c
@@ -92,7 +92,7 @@ static int blink_set(struct led_classdev *cdev,
return 0;
}
-static int __devinit asic3_led_probe(struct platform_device *pdev)
+static int asic3_led_probe(struct platform_device *pdev)
{
struct asic3_led *led = pdev->dev.platform_data;
int ret;
@@ -125,7 +125,7 @@ out:
return ret;
}
-static int __devexit asic3_led_remove(struct platform_device *pdev)
+static int asic3_led_remove(struct platform_device *pdev)
{
struct asic3_led *led = pdev->dev.platform_data;
@@ -167,7 +167,7 @@ static const struct dev_pm_ops asic3_led_pm_ops = {
static struct platform_driver asic3_led_driver = {
.probe = asic3_led_probe,
- .remove = __devexit_p(asic3_led_remove),
+ .remove = asic3_led_remove,
.driver = {
.name = "leds-asic3",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c
index 45430632faab..386773532d95 100644
--- a/drivers/leds/leds-atmel-pwm.c
+++ b/drivers/leds/leds-atmel-pwm.c
@@ -35,7 +35,7 @@ static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b)
* NOTE: we reuse the platform_data structure of GPIO leds,
* but repurpose its "gpio" number as a PWM channel number.
*/
-static int __devinit pwmled_probe(struct platform_device *pdev)
+static int pwmled_probe(struct platform_device *pdev)
{
const struct gpio_led_platform_data *pdata;
struct pwmled *leds;
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 89ca6a2a19d1..851517030cc1 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -26,8 +26,8 @@
#define BD2802_LED_OFFSET 0xa
#define BD2802_COLOR_OFFSET 0x3
-#define BD2802_REG_CLKSETUP 0x00
-#define BD2802_REG_CONTROL 0x01
+#define BD2802_REG_CLKSETUP 0x00
+#define BD2802_REG_CONTROL 0x01
#define BD2802_REG_HOURSETUP 0x02
#define BD2802_REG_CURRENT1SETUP 0x03
#define BD2802_REG_CURRENT2SETUP 0x04
@@ -93,7 +93,7 @@ struct bd2802_led {
* In ADF mode, user can set registers of BD2802GU directly,
* therefore BD2802GU doesn't enter reset state.
*/
- int adf_on;
+ int adf_on;
enum led_ids led_id;
enum led_colors color;
@@ -328,7 +328,7 @@ static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
int ret; \
if (!count) \
return -EINVAL; \
- ret = strict_strtoul(buf, 16, &val); \
+ ret = kstrtoul(buf, 16, &val); \
if (ret) \
return ret; \
down_write(&led->rwsem); \
@@ -492,7 +492,7 @@ static ssize_t bd2802_store_##attr_name(struct device *dev, \
int ret; \
if (!count) \
return -EINVAL; \
- ret = strict_strtoul(buf, 16, &val); \
+ ret = kstrtoul(buf, 16, &val); \
if (ret) \
return ret; \
down_write(&led->rwsem); \
@@ -670,7 +670,7 @@ static void bd2802_unregister_led_classdev(struct bd2802_led *led)
led_classdev_unregister(&led->cdev_led1r);
}
-static int __devinit bd2802_probe(struct i2c_client *client,
+static int bd2802_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct bd2802_led *led;
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index f7c3d7f1ec52..a502678cc7f5 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -632,7 +632,7 @@ static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
return 0;
}
-static int __devinit blinkm_probe(struct i2c_client *client,
+static int blinkm_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct blinkm_data *data;
@@ -743,7 +743,7 @@ exit:
return err;
}
-static int __devexit blinkm_remove(struct i2c_client *client)
+static int blinkm_remove(struct i2c_client *client)
{
struct blinkm_data *data = i2c_get_clientdata(client);
int ret = 0;
@@ -801,7 +801,7 @@ static struct i2c_driver blinkm_driver = {
.name = "blinkm",
},
.probe = blinkm_probe,
- .remove = __devexit_p(blinkm_remove),
+ .remove = blinkm_remove,
.id_table = blinkm_id,
.detect = blinkm_detect,
.address_list = normal_i2c,
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index e024b0b1c3b1..6a8405df76a3 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -1,3 +1,4 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
@@ -26,7 +27,7 @@ static struct platform_device *pdev;
static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
{
- printk(KERN_INFO KBUILD_MODNAME ": '%s' found\n", id->ident);
+ pr_info("'%s' found\n", id->ident);
return 1;
}
@@ -135,8 +136,7 @@ static int clevo_mail_led_blink(struct led_classdev *led_cdev,
status = 0;
} else {
- printk(KERN_DEBUG KBUILD_MODNAME
- ": clevo_mail_led_blink(..., %lu, %lu),"
+ pr_debug("clevo_mail_led_blink(..., %lu, %lu),"
" returning -EINVAL (unsupported)\n",
*delay_on, *delay_off);
}
@@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = {
.flags = LED_CORE_SUSPENDRESUME,
};
-static int __devinit clevo_mail_led_probe(struct platform_device *pdev)
+static int clevo_mail_led_probe(struct platform_device *pdev)
{
return led_classdev_register(&pdev->dev, &clevo_mail_led);
}
@@ -183,7 +183,7 @@ static int __init clevo_mail_led_init(void)
count = dmi_check_system(clevo_mail_led_dmi_table);
} else {
count = 1;
- printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
+ pr_err("Skipping DMI detection. "
"If the driver works on your hardware please "
"report model and the output of dmidecode in tracker "
"at http://sourceforge.net/projects/clevo-mailled/\n");
@@ -197,8 +197,7 @@ static int __init clevo_mail_led_init(void)
error = platform_driver_probe(&clevo_mail_led_driver,
clevo_mail_led_probe);
if (error) {
- printk(KERN_ERR KBUILD_MODNAME
- ": Can't probe platform driver\n");
+ pr_err("Can't probe platform driver\n");
platform_device_unregister(pdev);
}
} else
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
index 6a8725cc7b4d..8abcb66db01c 100644
--- a/drivers/leds/leds-cobalt-qube.c
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -34,7 +34,7 @@ static struct led_classdev qube_front_led = {
.default_trigger = "default-on",
};
-static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
+static int cobalt_qube_led_probe(struct platform_device *pdev)
{
struct resource *res;
int retval;
@@ -43,7 +43,7 @@ static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
if (!res)
return -EBUSY;
- led_port = ioremap(res->start, resource_size(res));
+ led_port = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!led_port)
return -ENOMEM;
@@ -52,32 +52,29 @@ static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
retval = led_classdev_register(&pdev->dev, &qube_front_led);
if (retval)
- goto err_iounmap;
+ goto err_null;
return 0;
-err_iounmap:
- iounmap(led_port);
+err_null:
led_port = NULL;
return retval;
}
-static int __devexit cobalt_qube_led_remove(struct platform_device *pdev)
+static int cobalt_qube_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&qube_front_led);
- if (led_port) {
- iounmap(led_port);
+ if (led_port)
led_port = NULL;
- }
return 0;
}
static struct platform_driver cobalt_qube_led_driver = {
.probe = cobalt_qube_led_probe,
- .remove = __devexit_p(cobalt_qube_led_remove),
+ .remove = cobalt_qube_led_remove,
.driver = {
.name = "cobalt-qube-leds",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
index aac1c073fe7b..001088b31373 100644
--- a/drivers/leds/leds-cobalt-raq.c
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -76,7 +76,7 @@ static struct led_classdev raq_power_off_led = {
.default_trigger = "power-off",
};
-static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
+static int cobalt_raq_led_probe(struct platform_device *pdev)
{
struct resource *res;
int retval;
@@ -85,13 +85,13 @@ static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
if (!res)
return -EBUSY;
- led_port = ioremap(res->start, resource_size(res));
+ led_port = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!led_port)
return -ENOMEM;
retval = led_classdev_register(&pdev->dev, &raq_power_off_led);
if (retval)
- goto err_iounmap;
+ goto err_null;
retval = led_classdev_register(&pdev->dev, &raq_web_led);
if (retval)
@@ -102,29 +102,26 @@ static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
err_unregister:
led_classdev_unregister(&raq_power_off_led);
-err_iounmap:
- iounmap(led_port);
+err_null:
led_port = NULL;
return retval;
}
-static int __devexit cobalt_raq_led_remove(struct platform_device *pdev)
+static int cobalt_raq_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&raq_power_off_led);
led_classdev_unregister(&raq_web_led);
- if (led_port) {
- iounmap(led_port);
+ if (led_port)
led_port = NULL;
- }
return 0;
}
static struct platform_driver cobalt_raq_led_driver = {
.probe = cobalt_raq_led_probe,
- .remove = __devexit_p(cobalt_raq_led_remove),
+ .remove = cobalt_raq_led_remove,
.driver = {
.name = "cobalt-raq-leds",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index cc77c9d92615..c263a21db829 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -2,10 +2,10 @@
* LEDs driver for Dialog Semiconductor DA9030/DA9034
*
* Copyright (C) 2008 Compulab, Ltd.
- * Mike Rapoport <mike@compulab.co.il>
+ * Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
- * Eric Miao <eric.miao@marvell.com>
+ * Eric Miao <eric.miao@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -85,13 +85,13 @@ static void da903x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct da903x_led *led;
-
+
led = container_of(led_cdev, struct da903x_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
}
-static int __devinit da903x_led_probe(struct platform_device *pdev)
+static int da903x_led_probe(struct platform_device *pdev)
{
struct led_info *pdata = pdev->dev.platform_data;
struct da903x_led *led;
@@ -136,7 +136,7 @@ static int __devinit da903x_led_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit da903x_led_remove(struct platform_device *pdev)
+static int da903x_led_remove(struct platform_device *pdev)
{
struct da903x_led *led = platform_get_drvdata(pdev);
@@ -150,13 +150,13 @@ static struct platform_driver da903x_led_driver = {
.owner = THIS_MODULE,
},
.probe = da903x_led_probe,
- .remove = __devexit_p(da903x_led_remove),
+ .remove = da903x_led_remove,
};
module_platform_driver(da903x_led_driver);
MODULE_DESCRIPTION("LEDs driver for Dialog Semiconductor DA9030/DA9034");
-MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
- "Mike Rapoport <mike@compulab.co.il>");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da903x-led");
diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c
index 58a5244c437e..efec43344e9f 100644
--- a/drivers/leds/leds-da9052.c
+++ b/drivers/leds/leds-da9052.c
@@ -102,7 +102,7 @@ static int da9052_configure_leds(struct da9052 *da9052)
return error;
}
-static int __devinit da9052_led_probe(struct platform_device *pdev)
+static int da9052_led_probe(struct platform_device *pdev)
{
struct da9052_pdata *pdata;
struct da9052 *da9052;
@@ -176,7 +176,7 @@ err:
return error;
}
-static int __devexit da9052_led_remove(struct platform_device *pdev)
+static int da9052_led_remove(struct platform_device *pdev)
{
struct da9052_led *led = platform_get_drvdata(pdev);
struct da9052_pdata *pdata;
@@ -204,7 +204,7 @@ static struct platform_driver da9052_led_driver = {
.owner = THIS_MODULE,
},
.probe = da9052_led_probe,
- .remove = __devexit_p(da9052_led_remove),
+ .remove = da9052_led_remove,
};
module_platform_driver(da9052_led_driver);
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index b9053fa6e253..b4d5a44cc41b 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -20,8 +20,8 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/io.h>
#define FSG_LED_WLAN_BIT 0
#define FSG_LED_WAN_BIT 1
@@ -149,11 +149,10 @@ static int fsg_led_probe(struct platform_device *pdev)
int ret;
/* Map the LED chip select address space */
- latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
- if (!latch_address) {
- ret = -ENOMEM;
- goto failremap;
- }
+ latch_address = (unsigned short *) devm_ioremap(&pdev->dev,
+ IXP4XX_EXP_BUS_BASE(2), 512);
+ if (!latch_address)
+ return -ENOMEM;
latch_value = 0xffff;
*latch_address = latch_value;
@@ -195,8 +194,6 @@ static int fsg_led_probe(struct platform_device *pdev)
failwan:
led_classdev_unregister(&fsg_wlan_led);
failwlan:
- iounmap(latch_address);
- failremap:
return ret;
}
@@ -210,8 +207,6 @@ static int fsg_led_remove(struct platform_device *pdev)
led_classdev_unregister(&fsg_sync_led);
led_classdev_unregister(&fsg_ring_led);
- iounmap(latch_address);
-
return 0;
}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 087d1e66f4f7..a0d931bcb37c 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -21,6 +21,7 @@
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
struct gpio_led_data {
struct led_classdev cdev;
@@ -91,7 +92,7 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
delay_on, delay_off);
}
-static int __devinit create_gpio_led(const struct gpio_led *template,
+static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
{
@@ -101,15 +102,11 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
- printk(KERN_INFO "Skipping unavailable LED gpio %d (%s)\n",
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
template->gpio, template->name);
return 0;
}
- ret = gpio_request(template->gpio, template->name);
- if (ret < 0)
- return ret;
-
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
@@ -129,20 +126,20 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = devm_gpio_request_one(parent, template->gpio,
+ (led_dat->active_low ^ state) ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+ template->name);
if (ret < 0)
- goto err;
-
+ return ret;
+
INIT_WORK(&led_dat->work, gpio_led_work);
ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < 0)
- goto err;
+ return ret;
return 0;
-err:
- gpio_free(led_dat->gpio);
- return ret;
}
static void delete_gpio_led(struct gpio_led_data *led)
@@ -151,7 +148,6 @@ static void delete_gpio_led(struct gpio_led_data *led)
return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
- gpio_free(led->gpio);
}
struct gpio_leds_priv {
@@ -167,7 +163,7 @@ static inline int sizeof_gpio_leds_priv(int num_leds)
/* Code to create from OpenFirmware platform devices */
#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node, *child;
struct gpio_leds_priv *priv;
@@ -176,12 +172,16 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
/* count LEDs in this device, so we know how much to allocate */
count = of_get_child_count(np);
if (!count)
- return NULL;
+ return ERR_PTR(-ENODEV);
+
+ for_each_child_of_node(np, child)
+ if (of_get_gpio(child, 0) == -EPROBE_DEFER)
+ return ERR_PTR(-EPROBE_DEFER);
priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
GFP_KERNEL);
if (!priv)
- return NULL;
+ return ERR_PTR(-ENOMEM);
for_each_child_of_node(np, child) {
struct gpio_led led = {};
@@ -216,7 +216,7 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
err:
for (count = priv->num_leds - 2; count >= 0; count--)
delete_gpio_led(&priv->leds[count]);
- return NULL;
+ return ERR_PTR(-ENODEV);
}
static const struct of_device_id of_gpio_leds_match[] = {
@@ -224,14 +224,14 @@ static const struct of_device_id of_gpio_leds_match[] = {
{},
};
#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{
- return NULL;
+ return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_OF_GPIO */
-static int __devinit gpio_led_probe(struct platform_device *pdev)
+static int gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
@@ -264,8 +264,8 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
}
} else {
priv = gpio_leds_create_of(pdev);
- if (!priv)
- return -ENODEV;
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
}
platform_set_drvdata(pdev, priv);
@@ -273,7 +273,7 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit gpio_led_remove(struct platform_device *pdev)
+static int gpio_led_remove(struct platform_device *pdev)
{
struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
int i;
@@ -288,7 +288,7 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
- .remove = __devexit_p(gpio_led_remove),
+ .remove = gpio_led_remove,
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index b26306f6724d..a036a19040fe 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -187,6 +187,40 @@ static void lm3530_als_configure(struct lm3530_platform_data *pdata,
(pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
}
+static int lm3530_led_enable(struct lm3530_data *drvdata)
+{
+ int ret;
+
+ if (drvdata->enable)
+ return 0;
+
+ ret = regulator_enable(drvdata->regulator);
+ if (ret) {
+ dev_err(drvdata->led_dev.dev, "Failed to enable vin:%d\n", ret);
+ return ret;
+ }
+
+ drvdata->enable = true;
+ return 0;
+}
+
+static void lm3530_led_disable(struct lm3530_data *drvdata)
+{
+ int ret;
+
+ if (!drvdata->enable)
+ return;
+
+ ret = regulator_disable(drvdata->regulator);
+ if (ret) {
+ dev_err(drvdata->led_dev.dev, "Failed to disable vin:%d\n",
+ ret);
+ return;
+ }
+
+ drvdata->enable = false;
+}
+
static int lm3530_init_registers(struct lm3530_data *drvdata)
{
int ret = 0;
@@ -245,15 +279,9 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
reg_val[12] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */
reg_val[13] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */
- if (!drvdata->enable) {
- ret = regulator_enable(drvdata->regulator);
- if (ret) {
- dev_err(&drvdata->client->dev,
- "Enable regulator failed\n");
- return ret;
- }
- drvdata->enable = true;
- }
+ ret = lm3530_led_enable(drvdata);
+ if (ret)
+ return ret;
for (i = 0; i < LM3530_REG_MAX; i++) {
/* do not update brightness register when pwm mode */
@@ -305,13 +333,8 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
else
drvdata->brightness = brt_val;
- if (brt_val == 0) {
- err = regulator_disable(drvdata->regulator);
- if (err)
- dev_err(&drvdata->client->dev,
- "Disable regulator failed\n");
- drvdata->enable = false;
- }
+ if (brt_val == 0)
+ lm3530_led_disable(drvdata);
break;
case LM3530_BL_MODE_ALS:
break;
@@ -377,7 +400,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
}
static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
-static int __devinit lm3530_probe(struct i2c_client *client,
+static int lm3530_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lm3530_platform_data *pdata = client->dev.platform_data;
@@ -452,14 +475,13 @@ err_create_file:
return err;
}
-static int __devexit lm3530_remove(struct i2c_client *client)
+static int lm3530_remove(struct i2c_client *client)
{
struct lm3530_data *drvdata = i2c_get_clientdata(client);
device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
- if (drvdata->enable)
- regulator_disable(drvdata->regulator);
+ lm3530_led_disable(drvdata);
led_classdev_unregister(&drvdata->led_dev);
return 0;
}
@@ -472,7 +494,7 @@ MODULE_DEVICE_TABLE(i2c, lm3530_id);
static struct i2c_driver lm3530_i2c_driver = {
.probe = lm3530_probe,
- .remove = __devexit_p(lm3530_remove),
+ .remove = lm3530_remove,
.id_table = lm3530_id,
.driver = {
.name = LM3530_NAME,
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index f6837b99908c..bbf24d038a7f 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -646,7 +646,7 @@ static struct attribute_group lm3533_led_attribute_group = {
.attrs = lm3533_led_attributes
};
-static int __devinit lm3533_led_setup(struct lm3533_led *led,
+static int lm3533_led_setup(struct lm3533_led *led,
struct lm3533_led_platform_data *pdata)
{
int ret;
@@ -658,7 +658,7 @@ static int __devinit lm3533_led_setup(struct lm3533_led *led,
return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm);
}
-static int __devinit lm3533_led_probe(struct platform_device *pdev)
+static int lm3533_led_probe(struct platform_device *pdev)
{
struct lm3533 *lm3533;
struct lm3533_led_platform_data *pdata;
@@ -742,7 +742,7 @@ err_unregister:
return ret;
}
-static int __devexit lm3533_led_remove(struct platform_device *pdev)
+static int lm3533_led_remove(struct platform_device *pdev)
{
struct lm3533_led *led = platform_get_drvdata(pdev);
@@ -774,7 +774,7 @@ static struct platform_driver lm3533_led_driver = {
.owner = THIS_MODULE,
},
.probe = lm3533_led_probe,
- .remove = __devexit_p(lm3533_led_remove),
+ .remove = lm3533_led_remove,
.shutdown = lm3533_led_shutdown,
};
module_platform_driver(lm3533_led_driver);
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
index 065ec015d67a..4117235ba618 100644
--- a/drivers/leds/leds-lm355x.c
+++ b/drivers/leds/leds-lm355x.c
@@ -168,7 +168,7 @@ static char lm355x_name[][I2C_NAME_SIZE] = {
};
/* chip initialize */
-static int __devinit lm355x_chip_init(struct lm355x_chip_data *chip)
+static int lm355x_chip_init(struct lm355x_chip_data *chip)
{
int ret;
unsigned int reg_val;
@@ -380,7 +380,7 @@ static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
/* indicator pattern only for lm3556*/
static ssize_t lm3556_indicator_pattern_store(struct device *dev,
- struct device_attribute *devAttr,
+ struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t ret;
@@ -408,10 +408,10 @@ static ssize_t lm3556_indicator_pattern_store(struct device *dev,
return size;
out:
dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return size;
+ return ret;
}
-static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
+static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store);
static const struct regmap_config lm355x_regmap = {
.reg_bits = 8,
@@ -420,7 +420,7 @@ static const struct regmap_config lm355x_regmap = {
};
/* module initialize */
-static int __devinit lm355x_probe(struct i2c_client *client,
+static int lm355x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lm355x_platform_data *pdata = client->dev.platform_data;
@@ -526,7 +526,7 @@ err_out:
return err;
}
-static int __devexit lm355x_remove(struct i2c_client *client)
+static int lm355x_remove(struct i2c_client *client)
{
struct lm355x_chip_data *chip = i2c_get_clientdata(client);
struct lm355x_reg_data *preg = chip->regs;
@@ -560,7 +560,7 @@ static struct i2c_driver lm355x_i2c_driver = {
.pm = NULL,
},
.probe = lm355x_probe,
- .remove = __devexit_p(lm355x_remove),
+ .remove = lm355x_remove,
.id_table = lm355x_id,
};
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index 3285006e9888..9f428d9dfe91 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -93,7 +93,7 @@ struct lm3642_chip_data {
};
/* chip initialize */
-static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip)
+static int lm3642_chip_init(struct lm3642_chip_data *chip)
{
int ret;
struct lm3642_platform_data *pdata = chip->pdata;
@@ -176,7 +176,7 @@ out:
/* torch pin config for lm3642*/
static ssize_t lm3642_torch_pin_store(struct device *dev,
- struct device_attribute *devAttr,
+ struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t ret;
@@ -201,13 +201,13 @@ static ssize_t lm3642_torch_pin_store(struct device *dev,
return size;
out:
dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return size;
+ return ret;
out_strtoint:
dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
- return size;
+ return ret;
}
-static DEVICE_ATTR(torch_pin, 0666, NULL, lm3642_torch_pin_store);
+static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
{
@@ -233,7 +233,7 @@ static void lm3642_torch_brightness_set(struct led_classdev *cdev,
/* strobe pin config for lm3642*/
static ssize_t lm3642_strobe_pin_store(struct device *dev,
- struct device_attribute *devAttr,
+ struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t ret;
@@ -258,13 +258,13 @@ static ssize_t lm3642_strobe_pin_store(struct device *dev,
return size;
out:
dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return size;
+ return ret;
out_strtoint:
dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
- return size;
+ return ret;
}
-static DEVICE_ATTR(strobe_pin, 0666, NULL, lm3642_strobe_pin_store);
+static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
{
@@ -313,7 +313,7 @@ static const struct regmap_config lm3642_regmap = {
.max_register = REG_MAX,
};
-static int __devinit lm3642_probe(struct i2c_client *client,
+static int lm3642_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lm3642_platform_data *pdata = client->dev.platform_data;
@@ -420,7 +420,7 @@ err_out:
return err;
}
-static int __devexit lm3642_remove(struct i2c_client *client)
+static int lm3642_remove(struct i2c_client *client)
{
struct lm3642_chip_data *chip = i2c_get_clientdata(client);
@@ -450,7 +450,7 @@ static struct i2c_driver lm3642_i2c_driver = {
.pm = NULL,
},
.probe = lm3642_probe,
- .remove = __devexit_p(lm3642_remove),
+ .remove = lm3642_remove,
.id_table = lm3642_id,
};
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index c298f7d9f535..0c4386e656c1 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -86,7 +86,7 @@ static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value)
tmp = i2c_smbus_read_byte_data(client, reg);
if (tmp < 0)
- return -EINVAL;
+ return tmp;
*value = tmp;
@@ -374,7 +374,7 @@ exit:
return err;
}
-static int __devinit lp3944_probe(struct i2c_client *client,
+static int lp3944_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
@@ -411,7 +411,7 @@ static int __devinit lp3944_probe(struct i2c_client *client,
return 0;
}
-static int __devexit lp3944_remove(struct i2c_client *client)
+static int lp3944_remove(struct i2c_client *client)
{
struct lp3944_platform_data *pdata = client->dev.platform_data;
struct lp3944_data *data = i2c_get_clientdata(client);
@@ -446,7 +446,7 @@ static struct i2c_driver lp3944_driver = {
.name = "lp3944",
},
.probe = lp3944_probe,
- .remove = __devexit_p(lp3944_remove),
+ .remove = lp3944_remove,
.id_table = lp3944_id,
};
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 2064aefedc07..1001347ba70b 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -2,8 +2,10 @@
* LP5521 LED chip driver.
*
* Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments
*
* Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ * Milo(Woogyom) Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,33 +22,21 @@
* 02110-1301 USA
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
#include <linux/leds.h>
-#include <linux/leds-lp5521.h>
-#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/leds-lp55xx.h>
#include <linux/slab.h>
-#define LP5521_PROGRAM_LENGTH 32 /* in bytes */
-
-#define LP5521_MAX_LEDS 3 /* Maximum number of LEDs */
-#define LP5521_MAX_ENGINES 3 /* Maximum number of engines */
+#include "leds-lp55xx-common.h"
-#define LP5521_ENG_MASK_BASE 0x30 /* 00110000 */
-#define LP5521_ENG_STATUS_MASK 0x07 /* 00000111 */
-
-#define LP5521_CMD_LOAD 0x15 /* 00010101 */
-#define LP5521_CMD_RUN 0x2a /* 00101010 */
-#define LP5521_CMD_DIRECT 0x3f /* 00111111 */
-#define LP5521_CMD_DISABLED 0x00 /* 00000000 */
+#define LP5521_PROGRAM_LENGTH 32
+#define LP5521_MAX_LEDS 3
+#define LP5521_CMD_DIRECT 0x3F
/* Registers */
#define LP5521_REG_ENABLE 0x00
@@ -58,22 +48,14 @@
#define LP5521_REG_G_CURRENT 0x06
#define LP5521_REG_B_CURRENT 0x07
#define LP5521_REG_CONFIG 0x08
-#define LP5521_REG_R_CHANNEL_PC 0x09
-#define LP5521_REG_G_CHANNEL_PC 0x0A
-#define LP5521_REG_B_CHANNEL_PC 0x0B
#define LP5521_REG_STATUS 0x0C
#define LP5521_REG_RESET 0x0D
-#define LP5521_REG_GPO 0x0E
#define LP5521_REG_R_PROG_MEM 0x10
#define LP5521_REG_G_PROG_MEM 0x30
#define LP5521_REG_B_PROG_MEM 0x50
-#define LP5521_PROG_MEM_BASE LP5521_REG_R_PROG_MEM
-#define LP5521_PROG_MEM_SIZE 0x20
-
/* Base register to set LED current */
#define LP5521_REG_LED_CURRENT_BASE LP5521_REG_R_CURRENT
-
/* Base register to set the brightness */
#define LP5521_REG_LED_PWM_BASE LP5521_REG_R_PWM
@@ -92,440 +74,287 @@
/* default R channel current register value */
#define LP5521_REG_R_CURR_DEFAULT 0xAF
-/* Pattern Mode */
-#define PATTERN_OFF 0
+/* Reset register value */
+#define LP5521_RESET 0xFF
-struct lp5521_engine {
- int id;
- u8 mode;
- u8 prog_page;
- u8 engine_mask;
-};
+/* Program Memory Operations */
+#define LP5521_MODE_R_M 0x30 /* Operation Mode Register */
+#define LP5521_MODE_G_M 0x0C
+#define LP5521_MODE_B_M 0x03
+#define LP5521_LOAD_R 0x10
+#define LP5521_LOAD_G 0x04
+#define LP5521_LOAD_B 0x01
-struct lp5521_led {
- int id;
- u8 chan_nr;
- u8 led_current;
- u8 max_current;
- struct led_classdev cdev;
- struct work_struct brightness_work;
- u8 brightness;
-};
+#define LP5521_R_IS_LOADING(mode) \
+ ((mode & LP5521_MODE_R_M) == LP5521_LOAD_R)
+#define LP5521_G_IS_LOADING(mode) \
+ ((mode & LP5521_MODE_G_M) == LP5521_LOAD_G)
+#define LP5521_B_IS_LOADING(mode) \
+ ((mode & LP5521_MODE_B_M) == LP5521_LOAD_B)
-struct lp5521_chip {
- struct lp5521_platform_data *pdata;
- struct mutex lock; /* Serialize control */
- struct i2c_client *client;
- struct lp5521_engine engines[LP5521_MAX_ENGINES];
- struct lp5521_led leds[LP5521_MAX_LEDS];
- u8 num_channels;
- u8 num_leds;
-};
+#define LP5521_EXEC_R_M 0x30 /* Enable Register */
+#define LP5521_EXEC_G_M 0x0C
+#define LP5521_EXEC_B_M 0x03
+#define LP5521_EXEC_M 0x3F
+#define LP5521_RUN_R 0x20
+#define LP5521_RUN_G 0x08
+#define LP5521_RUN_B 0x02
-static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev)
+static inline void lp5521_wait_opmode_done(void)
{
- return container_of(cdev, struct lp5521_led, cdev);
+ /* operation mode change needs to be longer than 153 us */
+ usleep_range(200, 300);
}
-static inline struct lp5521_chip *engine_to_lp5521(struct lp5521_engine *engine)
+static inline void lp5521_wait_enable_done(void)
{
- return container_of(engine, struct lp5521_chip,
- engines[engine->id - 1]);
+ /* it takes more 488 us to update ENABLE register */
+ usleep_range(500, 600);
}
-static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led)
+static void lp5521_set_led_current(struct lp55xx_led *led, u8 led_current)
{
- return container_of(led, struct lp5521_chip,
- leds[led->id]);
+ led->led_current = led_current;
+ lp55xx_write(led->chip, LP5521_REG_LED_CURRENT_BASE + led->chan_nr,
+ led_current);
}
-static void lp5521_led_brightness_work(struct work_struct *work);
-
-static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+static void lp5521_load_engine(struct lp55xx_chip *chip)
{
- return i2c_smbus_write_byte_data(client, reg, value);
-}
+ enum lp55xx_engine_index idx = chip->engine_idx;
+ u8 mask[] = {
+ [LP55XX_ENGINE_1] = LP5521_MODE_R_M,
+ [LP55XX_ENGINE_2] = LP5521_MODE_G_M,
+ [LP55XX_ENGINE_3] = LP5521_MODE_B_M,
+ };
-static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
-{
- s32 ret;
+ u8 val[] = {
+ [LP55XX_ENGINE_1] = LP5521_LOAD_R,
+ [LP55XX_ENGINE_2] = LP5521_LOAD_G,
+ [LP55XX_ENGINE_3] = LP5521_LOAD_B,
+ };
- ret = i2c_smbus_read_byte_data(client, reg);
- if (ret < 0)
- return -EIO;
+ lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], val[idx]);
- *buf = ret;
- return 0;
+ lp5521_wait_opmode_done();
}
-static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode)
+static void lp5521_stop_engine(struct lp55xx_chip *chip)
{
- struct lp5521_chip *chip = engine_to_lp5521(engine);
- struct i2c_client *client = chip->client;
- int ret;
- u8 engine_state;
-
- /* Only transition between RUN and DIRECT mode are handled here */
- if (mode == LP5521_CMD_LOAD)
- return 0;
-
- if (mode == LP5521_CMD_DISABLED)
- mode = LP5521_CMD_DIRECT;
-
- ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state);
- if (ret < 0)
- return ret;
-
- /* set mode only for this engine */
- engine_state &= ~(engine->engine_mask);
- mode &= engine->engine_mask;
- engine_state |= mode;
- return lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
+ lp55xx_write(chip, LP5521_REG_OP_MODE, 0);
+ lp5521_wait_opmode_done();
}
-static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
+static void lp5521_run_engine(struct lp55xx_chip *chip, bool start)
{
- struct lp5521_chip *chip = engine_to_lp5521(eng);
- struct i2c_client *client = chip->client;
int ret;
- int addr;
u8 mode;
+ u8 exec;
- /* move current engine to direct mode and remember the state */
- ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
- if (ret)
- return ret;
-
- /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
- usleep_range(1000, 2000);
- ret = lp5521_read(client, LP5521_REG_OP_MODE, &mode);
- if (ret)
- return ret;
-
- /* For loading, all the engines to load mode */
- lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
- /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
- usleep_range(1000, 2000);
- lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
- /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
- usleep_range(1000, 2000);
-
- addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE;
- i2c_smbus_write_i2c_block_data(client,
- addr,
- LP5521_PROG_MEM_SIZE,
- pattern);
-
- return lp5521_write(client, LP5521_REG_OP_MODE, mode);
-}
-
-static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
-{
- return lp5521_write(chip->client,
- LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
- curr);
-}
-
-static void lp5521_init_engine(struct lp5521_chip *chip)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
- chip->engines[i].id = i + 1;
- chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2);
- chip->engines[i].prog_page = i;
+ /* stop engine */
+ if (!start) {
+ lp5521_stop_engine(chip);
+ lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+ lp5521_wait_opmode_done();
+ return;
}
-}
-
-static int lp5521_configure(struct i2c_client *client)
-{
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- int ret;
- u8 cfg;
-
- lp5521_init_engine(chip);
-
- /* Set all PWMs to direct control mode */
- ret = lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
-
- cfg = chip->pdata->update_config ?
- : (LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
- ret |= lp5521_write(client, LP5521_REG_CONFIG, cfg);
-
- /* Initialize all channels PWM to zero -> leds off */
- ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
- ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
- ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
-
- /* Set engines are set to run state when OP_MODE enables engines */
- ret |= lp5521_write(client, LP5521_REG_ENABLE,
- LP5521_ENABLE_RUN_PROGRAM);
- /* enable takes 500us. 1 - 2 ms leaves some margin */
- usleep_range(1000, 2000);
-
- return ret;
-}
-
-static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf)
-{
- int ret;
- u8 status;
-
- ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status);
- if (ret < 0)
- return ret;
-
- /* Check that ext clock is really in use if requested */
- if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT)
- if ((status & LP5521_EXT_CLK_USED) == 0)
- return -EIO;
- return 0;
-}
-static void lp5521_set_brightness(struct led_classdev *cdev,
- enum led_brightness brightness)
-{
- struct lp5521_led *led = cdev_to_led(cdev);
- led->brightness = (u8)brightness;
- schedule_work(&led->brightness_work);
-}
-
-static void lp5521_led_brightness_work(struct work_struct *work)
-{
- struct lp5521_led *led = container_of(work,
- struct lp5521_led,
- brightness_work);
- struct lp5521_chip *chip = led_to_lp5521(led);
- struct i2c_client *client = chip->client;
-
- mutex_lock(&chip->lock);
- lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr,
- led->brightness);
- mutex_unlock(&chip->lock);
-}
-
-/* Detect the chip by setting its ENABLE register and reading it back. */
-static int lp5521_detect(struct i2c_client *client)
-{
- int ret;
- u8 buf;
+ /*
+ * To run the engine,
+ * operation mode and enable register should updated at the same time
+ */
- ret = lp5521_write(client, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
- if (ret)
- return ret;
- /* enable takes 500us. 1 - 2 ms leaves some margin */
- usleep_range(1000, 2000);
- ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
+ ret = lp55xx_read(chip, LP5521_REG_OP_MODE, &mode);
if (ret)
- return ret;
- if (buf != LP5521_ENABLE_DEFAULT)
- return -ENODEV;
+ return;
- return 0;
-}
+ ret = lp55xx_read(chip, LP5521_REG_ENABLE, &exec);
+ if (ret)
+ return;
-/* Set engine mode and create appropriate sysfs attributes, if required. */
-static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode)
-{
- int ret = 0;
+ /* change operation mode to RUN only when each engine is loading */
+ if (LP5521_R_IS_LOADING(mode)) {
+ mode = (mode & ~LP5521_MODE_R_M) | LP5521_RUN_R;
+ exec = (exec & ~LP5521_EXEC_R_M) | LP5521_RUN_R;
+ }
- /* if in that mode already do nothing, except for run */
- if (mode == engine->mode && mode != LP5521_CMD_RUN)
- return 0;
+ if (LP5521_G_IS_LOADING(mode)) {
+ mode = (mode & ~LP5521_MODE_G_M) | LP5521_RUN_G;
+ exec = (exec & ~LP5521_EXEC_G_M) | LP5521_RUN_G;
+ }
- if (mode == LP5521_CMD_RUN) {
- ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN);
- } else if (mode == LP5521_CMD_LOAD) {
- lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
- lp5521_set_engine_mode(engine, LP5521_CMD_LOAD);
- } else if (mode == LP5521_CMD_DISABLED) {
- lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+ if (LP5521_B_IS_LOADING(mode)) {
+ mode = (mode & ~LP5521_MODE_B_M) | LP5521_RUN_B;
+ exec = (exec & ~LP5521_EXEC_B_M) | LP5521_RUN_B;
}
- engine->mode = mode;
+ lp55xx_write(chip, LP5521_REG_OP_MODE, mode);
+ lp5521_wait_opmode_done();
- return ret;
+ lp55xx_update_bits(chip, LP5521_REG_ENABLE, LP5521_EXEC_M, exec);
+ lp5521_wait_enable_done();
}
-static int lp5521_do_store_load(struct lp5521_engine *engine,
- const char *buf, size_t len)
+static int lp5521_update_program_memory(struct lp55xx_chip *chip,
+ const u8 *data, size_t size)
{
- struct lp5521_chip *chip = engine_to_lp5521(engine);
- struct i2c_client *client = chip->client;
- int ret, nrchars, offset = 0, i = 0;
- char c[3];
- unsigned cmd;
+ enum lp55xx_engine_index idx = chip->engine_idx;
u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+ u8 addr[] = {
+ [LP55XX_ENGINE_1] = LP5521_REG_R_PROG_MEM,
+ [LP55XX_ENGINE_2] = LP5521_REG_G_PROG_MEM,
+ [LP55XX_ENGINE_3] = LP5521_REG_B_PROG_MEM,
+ };
+ unsigned cmd;
+ char c[3];
+ int program_size;
+ int nrchars;
+ int offset = 0;
+ int ret;
+ int i;
- while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+ /* clear program memory before updating */
+ for (i = 0; i < LP5521_PROGRAM_LENGTH; i++)
+ lp55xx_write(chip, addr[idx] + i, 0);
+
+ i = 0;
+ while ((offset < size - 1) && (i < LP5521_PROGRAM_LENGTH)) {
/* separate sscanfs because length is working only for %s */
- ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
- if (ret != 2)
- goto fail;
+ ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
+ if (ret != 1)
+ goto err;
+
ret = sscanf(c, "%2x", &cmd);
if (ret != 1)
- goto fail;
- pattern[i] = (u8)cmd;
+ goto err;
+ pattern[i] = (u8)cmd;
offset += nrchars;
i++;
}
/* Each instruction is 16bit long. Check that length is even */
if (i % 2)
- goto fail;
+ goto err;
- mutex_lock(&chip->lock);
- if (engine->mode == LP5521_CMD_LOAD)
- ret = lp5521_load_program(engine, pattern);
- else
- ret = -EINVAL;
- mutex_unlock(&chip->lock);
+ program_size = i;
+ for (i = 0; i < program_size; i++)
+ lp55xx_write(chip, addr[idx] + i, pattern[i]);
- if (ret) {
- dev_err(&client->dev, "failed loading pattern\n");
- return ret;
- }
+ return 0;
- return len;
-fail:
- dev_err(&client->dev, "wrong pattern format\n");
+err:
+ dev_err(&chip->cl->dev, "wrong pattern format\n");
return -EINVAL;
}
-static ssize_t store_engine_load(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len, int nr)
+static void lp5521_firmware_loaded(struct lp55xx_chip *chip)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- return lp5521_do_store_load(&chip->engines[nr - 1], buf, len);
-}
+ const struct firmware *fw = chip->fw;
-#define store_load(nr) \
-static ssize_t store_engine##nr##_load(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t len) \
-{ \
- return store_engine_load(dev, attr, buf, len, nr); \
-}
-store_load(1)
-store_load(2)
-store_load(3)
-
-static ssize_t show_engine_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf, int nr)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- switch (chip->engines[nr - 1].mode) {
- case LP5521_CMD_RUN:
- return sprintf(buf, "run\n");
- case LP5521_CMD_LOAD:
- return sprintf(buf, "load\n");
- case LP5521_CMD_DISABLED:
- return sprintf(buf, "disabled\n");
- default:
- return sprintf(buf, "disabled\n");
+ if (fw->size > LP5521_PROGRAM_LENGTH) {
+ dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
+ fw->size);
+ return;
}
-}
-#define show_mode(nr) \
-static ssize_t show_engine##nr##_mode(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_engine_mode(dev, attr, buf, nr); \
+ /*
+ * Program momery sequence
+ * 1) set engine mode to "LOAD"
+ * 2) write firmware data into program memory
+ */
+
+ lp5521_load_engine(chip);
+ lp5521_update_program_memory(chip, fw->data, fw->size);
}
-show_mode(1)
-show_mode(2)
-show_mode(3)
-static ssize_t store_engine_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len, int nr)
+static int lp5521_post_init_device(struct lp55xx_chip *chip)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- struct lp5521_engine *engine = &chip->engines[nr - 1];
- mutex_lock(&chip->lock);
+ int ret;
+ u8 val;
- if (!strncmp(buf, "run", 3))
- lp5521_set_mode(engine, LP5521_CMD_RUN);
- else if (!strncmp(buf, "load", 4))
- lp5521_set_mode(engine, LP5521_CMD_LOAD);
- else if (!strncmp(buf, "disabled", 8))
- lp5521_set_mode(engine, LP5521_CMD_DISABLED);
+ /*
+ * Make sure that the chip is reset by reading back the r channel
+ * current reg. This is dummy read is required on some platforms -
+ * otherwise further access to the R G B channels in the
+ * LP5521_REG_ENABLE register will not have any effect - strange!
+ */
+ ret = lp55xx_read(chip, LP5521_REG_R_CURRENT, &val);
+ if (ret) {
+ dev_err(&chip->cl->dev, "error in resetting chip\n");
+ return ret;
+ }
+ if (val != LP5521_REG_R_CURR_DEFAULT) {
+ dev_err(&chip->cl->dev,
+ "unexpected data in register (expected 0x%x got 0x%x)\n",
+ LP5521_REG_R_CURR_DEFAULT, val);
+ ret = -EINVAL;
+ return ret;
+ }
+ usleep_range(10000, 20000);
- mutex_unlock(&chip->lock);
- return len;
-}
+ /* Set all PWMs to direct control mode */
+ ret = lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
-#define store_mode(nr) \
-static ssize_t store_engine##nr##_mode(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t len) \
-{ \
- return store_engine_mode(dev, attr, buf, len, nr); \
-}
-store_mode(1)
-store_mode(2)
-store_mode(3)
+ val = chip->pdata->update_config ?
+ : (LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+ ret = lp55xx_write(chip, LP5521_REG_CONFIG, val);
+ if (ret)
+ return ret;
-static ssize_t show_max_current(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5521_led *led = cdev_to_led(led_cdev);
+ /* Initialize all channels PWM to zero -> leds off */
+ lp55xx_write(chip, LP5521_REG_R_PWM, 0);
+ lp55xx_write(chip, LP5521_REG_G_PWM, 0);
+ lp55xx_write(chip, LP5521_REG_B_PWM, 0);
- return sprintf(buf, "%d\n", led->max_current);
-}
+ /* Set engines are set to run state when OP_MODE enables engines */
+ ret = lp55xx_write(chip, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
+ if (ret)
+ return ret;
-static ssize_t show_current(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5521_led *led = cdev_to_led(led_cdev);
+ lp5521_wait_enable_done();
- return sprintf(buf, "%d\n", led->led_current);
+ return 0;
}
-static ssize_t store_current(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static int lp5521_run_selftest(struct lp55xx_chip *chip, char *buf)
{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5521_led *led = cdev_to_led(led_cdev);
- struct lp5521_chip *chip = led_to_lp5521(led);
- ssize_t ret;
- unsigned long curr;
+ struct lp55xx_platform_data *pdata = chip->pdata;
+ int ret;
+ u8 status;
- if (kstrtoul(buf, 0, &curr))
- return -EINVAL;
+ ret = lp55xx_read(chip, LP5521_REG_STATUS, &status);
+ if (ret < 0)
+ return ret;
- if (curr > led->max_current)
- return -EINVAL;
+ if (pdata->clock_mode != LP55XX_CLOCK_EXT)
+ return 0;
- mutex_lock(&chip->lock);
- ret = lp5521_set_led_current(chip, led->id, curr);
- mutex_unlock(&chip->lock);
+ /* Check that ext clock is really in use if requested */
+ if ((status & LP5521_EXT_CLK_USED) == 0)
+ return -EIO;
- if (ret < 0)
- return ret;
+ return 0;
+}
- led->led_current = (u8)curr;
+static void lp5521_led_brightness_work(struct work_struct *work)
+{
+ struct lp55xx_led *led = container_of(work, struct lp55xx_led,
+ brightness_work);
+ struct lp55xx_chip *chip = led->chip;
- return len;
+ mutex_lock(&chip->lock);
+ lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+ led->brightness);
+ mutex_unlock(&chip->lock);
}
static ssize_t lp5521_selftest(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5521_chip *chip = i2c_get_clientdata(client);
+ struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+ struct lp55xx_chip *chip = led->chip;
int ret;
mutex_lock(&chip->lock);
@@ -534,133 +363,11 @@ static ssize_t lp5521_selftest(struct device *dev,
return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
}
-static void lp5521_clear_program_memory(struct i2c_client *cl)
-{
- int i;
- u8 rgb_mem[] = {
- LP5521_REG_R_PROG_MEM,
- LP5521_REG_G_PROG_MEM,
- LP5521_REG_B_PROG_MEM,
- };
-
- for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
- lp5521_write(cl, rgb_mem[i], 0);
- lp5521_write(cl, rgb_mem[i] + 1, 0);
- }
-}
-
-static void lp5521_write_program_memory(struct i2c_client *cl,
- u8 base, u8 *rgb, int size)
-{
- int i;
-
- if (!rgb || size <= 0)
- return;
-
- for (i = 0; i < size; i++)
- lp5521_write(cl, base + i, *(rgb + i));
-
- lp5521_write(cl, base + i, 0);
- lp5521_write(cl, base + i + 1, 0);
-}
-
-static inline struct lp5521_led_pattern *lp5521_get_pattern
- (struct lp5521_chip *chip, u8 offset)
-{
- struct lp5521_led_pattern *ptn;
- ptn = chip->pdata->patterns + (offset - 1);
- return ptn;
-}
-
-static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
-{
- struct lp5521_led_pattern *ptn;
- struct i2c_client *cl = chip->client;
- int num_patterns = chip->pdata->num_patterns;
-
- if (mode > num_patterns || !(chip->pdata->patterns))
- return;
-
- if (mode == PATTERN_OFF) {
- lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
- usleep_range(1000, 2000);
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
- } else {
- ptn = lp5521_get_pattern(chip, mode);
- if (!ptn)
- return;
-
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
- usleep_range(1000, 2000);
-
- lp5521_clear_program_memory(cl);
-
- lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
- ptn->r, ptn->size_r);
- lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
- ptn->g, ptn->size_g);
- lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
- ptn->b, ptn->size_b);
-
- lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
- usleep_range(1000, 2000);
- lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
- }
-}
-
-static ssize_t store_led_pattern(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- lp5521_run_led_pattern(val, chip);
-
- return len;
-}
-
-/* led class device attributes */
-static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
-static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
-
-static struct attribute *lp5521_led_attributes[] = {
- &dev_attr_led_current.attr,
- &dev_attr_max_current.attr,
- NULL,
-};
-
-static struct attribute_group lp5521_led_attribute_group = {
- .attrs = lp5521_led_attributes
-};
-
/* device attributes */
-static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
- show_engine1_mode, store_engine1_mode);
-static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
- show_engine2_mode, store_engine2_mode);
-static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
- show_engine3_mode, store_engine3_mode);
-static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
-static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
-static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
-static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
static struct attribute *lp5521_attributes[] = {
- &dev_attr_engine1_mode.attr,
- &dev_attr_engine2_mode.attr,
- &dev_attr_engine3_mode.attr,
&dev_attr_selftest.attr,
- &dev_attr_engine1_load.attr,
- &dev_attr_engine2_load.attr,
- &dev_attr_engine3_load.attr,
- &dev_attr_led_pattern.attr,
NULL
};
@@ -668,210 +375,91 @@ static const struct attribute_group lp5521_group = {
.attrs = lp5521_attributes,
};
-static int lp5521_register_sysfs(struct i2c_client *client)
-{
- struct device *dev = &client->dev;
- return sysfs_create_group(&dev->kobj, &lp5521_group);
-}
-
-static void lp5521_unregister_sysfs(struct i2c_client *client)
-{
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- struct device *dev = &client->dev;
- int i;
-
- sysfs_remove_group(&dev->kobj, &lp5521_group);
-
- for (i = 0; i < chip->num_leds; i++)
- sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
- &lp5521_led_attribute_group);
-}
+/* Chip specific configurations */
+static struct lp55xx_device_config lp5521_cfg = {
+ .reset = {
+ .addr = LP5521_REG_RESET,
+ .val = LP5521_RESET,
+ },
+ .enable = {
+ .addr = LP5521_REG_ENABLE,
+ .val = LP5521_ENABLE_DEFAULT,
+ },
+ .max_channel = LP5521_MAX_LEDS,
+ .post_init_device = lp5521_post_init_device,
+ .brightness_work_fn = lp5521_led_brightness_work,
+ .set_led_current = lp5521_set_led_current,
+ .firmware_cb = lp5521_firmware_loaded,
+ .run_engine = lp5521_run_engine,
+ .dev_attr_group = &lp5521_group,
+};
-static int __devinit lp5521_init_led(struct lp5521_led *led,
- struct i2c_client *client,
- int chan, struct lp5521_platform_data *pdata)
+static int lp5521_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct device *dev = &client->dev;
- char name[32];
- int res;
-
- if (chan >= LP5521_MAX_LEDS)
- return -EINVAL;
-
- if (pdata->led_config[chan].led_current == 0)
- return 0;
-
- led->led_current = pdata->led_config[chan].led_current;
- led->max_current = pdata->led_config[chan].max_current;
- led->chan_nr = pdata->led_config[chan].chan_nr;
+ int ret;
+ struct lp55xx_chip *chip;
+ struct lp55xx_led *led;
+ struct lp55xx_platform_data *pdata = client->dev.platform_data;
- if (led->chan_nr >= LP5521_MAX_LEDS) {
- dev_err(dev, "Use channel numbers between 0 and %d\n",
- LP5521_MAX_LEDS - 1);
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data\n");
return -EINVAL;
}
- led->cdev.brightness_set = lp5521_set_brightness;
- if (pdata->led_config[chan].name) {
- led->cdev.name = pdata->led_config[chan].name;
- } else {
- snprintf(name, sizeof(name), "%s:channel%d",
- pdata->label ?: client->name, chan);
- led->cdev.name = name;
- }
-
- res = led_classdev_register(dev, &led->cdev);
- if (res < 0) {
- dev_err(dev, "couldn't register led on channel %d\n", chan);
- return res;
- }
-
- res = sysfs_create_group(&led->cdev.dev->kobj,
- &lp5521_led_attribute_group);
- if (res < 0) {
- dev_err(dev, "couldn't register current attribute\n");
- led_classdev_unregister(&led->cdev);
- return res;
- }
- return 0;
-}
-
-static int __devinit lp5521_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct lp5521_chip *chip;
- struct lp5521_platform_data *pdata;
- int ret, i, led;
- u8 buf;
-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- i2c_set_clientdata(client, chip);
- chip->client = client;
-
- pdata = client->dev.platform_data;
+ led = devm_kzalloc(&client->dev,
+ sizeof(*led) * pdata->num_channels, GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
- if (!pdata) {
- dev_err(&client->dev, "no platform data\n");
- return -EINVAL;
- }
+ chip->cl = client;
+ chip->pdata = pdata;
+ chip->cfg = &lp5521_cfg;
mutex_init(&chip->lock);
- chip->pdata = pdata;
-
- if (pdata->setup_resources) {
- ret = pdata->setup_resources();
- if (ret < 0)
- return ret;
- }
-
- if (pdata->enable) {
- pdata->enable(0);
- usleep_range(1000, 2000); /* Keep enable down at least 1ms */
- pdata->enable(1);
- usleep_range(1000, 2000); /* 500us abs min. */
- }
-
- lp5521_write(client, LP5521_REG_RESET, 0xff);
- usleep_range(10000, 20000); /*
- * Exact value is not available. 10 - 20ms
- * appears to be enough for reset.
- */
+ i2c_set_clientdata(client, led);
- /*
- * Make sure that the chip is reset by reading back the r channel
- * current reg. This is dummy read is required on some platforms -
- * otherwise further access to the R G B channels in the
- * LP5521_REG_ENABLE register will not have any effect - strange!
- */
- ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
- if (ret || buf != LP5521_REG_R_CURR_DEFAULT) {
- dev_err(&client->dev, "error in resetting chip\n");
- goto fail2;
- }
- usleep_range(10000, 20000);
-
- ret = lp5521_detect(client);
-
- if (ret) {
- dev_err(&client->dev, "Chip not found\n");
- goto fail2;
- }
+ ret = lp55xx_init_device(chip);
+ if (ret)
+ goto err_init;
dev_info(&client->dev, "%s programmable led chip found\n", id->name);
- ret = lp5521_configure(client);
- if (ret < 0) {
- dev_err(&client->dev, "error configuring chip\n");
- goto fail1;
- }
-
- /* Initialize leds */
- chip->num_channels = pdata->num_channels;
- chip->num_leds = 0;
- led = 0;
- for (i = 0; i < pdata->num_channels; i++) {
- /* Do not initialize channels that are not connected */
- if (pdata->led_config[i].led_current == 0)
- continue;
-
- ret = lp5521_init_led(&chip->leds[led], client, i, pdata);
- if (ret) {
- dev_err(&client->dev, "error initializing leds\n");
- goto fail2;
- }
- chip->num_leds++;
-
- chip->leds[led].id = led;
- /* Set initial LED current */
- lp5521_set_led_current(chip, led,
- chip->leds[led].led_current);
-
- INIT_WORK(&(chip->leds[led].brightness_work),
- lp5521_led_brightness_work);
-
- led++;
- }
+ ret = lp55xx_register_leds(led, chip);
+ if (ret)
+ goto err_register_leds;
- ret = lp5521_register_sysfs(client);
+ ret = lp55xx_register_sysfs(chip);
if (ret) {
dev_err(&client->dev, "registering sysfs failed\n");
- goto fail2;
+ goto err_register_sysfs;
}
- return ret;
-fail2:
- for (i = 0; i < chip->num_leds; i++) {
- led_classdev_unregister(&chip->leds[i].cdev);
- cancel_work_sync(&chip->leds[i].brightness_work);
- }
-fail1:
- if (pdata->enable)
- pdata->enable(0);
- if (pdata->release_resources)
- pdata->release_resources();
+
+ return 0;
+
+err_register_sysfs:
+ lp55xx_unregister_leds(led, chip);
+err_register_leds:
+ lp55xx_deinit_device(chip);
+err_init:
return ret;
}
-static int __devexit lp5521_remove(struct i2c_client *client)
+static int lp5521_remove(struct i2c_client *client)
{
- struct lp5521_chip *chip = i2c_get_clientdata(client);
- int i;
+ struct lp55xx_led *led = i2c_get_clientdata(client);
+ struct lp55xx_chip *chip = led->chip;
- lp5521_run_led_pattern(PATTERN_OFF, chip);
- lp5521_unregister_sysfs(client);
-
- for (i = 0; i < chip->num_leds; i++) {
- led_classdev_unregister(&chip->leds[i].cdev);
- cancel_work_sync(&chip->leds[i].brightness_work);
- }
+ lp5521_stop_engine(chip);
+ lp55xx_unregister_sysfs(chip);
+ lp55xx_unregister_leds(led, chip);
+ lp55xx_deinit_device(chip);
- if (chip->pdata->enable)
- chip->pdata->enable(0);
- if (chip->pdata->release_resources)
- chip->pdata->release_resources();
return 0;
}
@@ -886,12 +474,13 @@ static struct i2c_driver lp5521_driver = {
.name = "lp5521",
},
.probe = lp5521_probe,
- .remove = __devexit_p(lp5521_remove),
+ .remove = lp5521_remove,
.id_table = lp5521_id,
};
module_i2c_driver(lp5521_driver);
MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
+MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
MODULE_DESCRIPTION("LP5521 LED engine");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 97994ffdc014..229f734040af 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -2,8 +2,10 @@
* lp5523.c - LP5523 LED Driver
*
* Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments
*
* Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ * Milo(Woogyom) Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,488 +22,351 @@
* 02110-1301 USA
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
#include <linux/leds.h>
-#include <linux/leds-lp5523.h>
-#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/leds-lp55xx.h>
#include <linux/slab.h>
+#include "leds-lp55xx-common.h"
+
+#define LP5523_PROGRAM_LENGTH 32
+#define LP5523_MAX_LEDS 9
+
+/* Registers */
#define LP5523_REG_ENABLE 0x00
#define LP5523_REG_OP_MODE 0x01
-#define LP5523_REG_RATIOMETRIC_MSB 0x02
-#define LP5523_REG_RATIOMETRIC_LSB 0x03
#define LP5523_REG_ENABLE_LEDS_MSB 0x04
#define LP5523_REG_ENABLE_LEDS_LSB 0x05
-#define LP5523_REG_LED_CNTRL_BASE 0x06
#define LP5523_REG_LED_PWM_BASE 0x16
#define LP5523_REG_LED_CURRENT_BASE 0x26
#define LP5523_REG_CONFIG 0x36
-#define LP5523_REG_CHANNEL1_PC 0x37
-#define LP5523_REG_CHANNEL2_PC 0x38
-#define LP5523_REG_CHANNEL3_PC 0x39
-#define LP5523_REG_STATUS 0x3a
-#define LP5523_REG_GPO 0x3b
-#define LP5523_REG_VARIABLE 0x3c
-#define LP5523_REG_RESET 0x3d
-#define LP5523_REG_TEMP_CTRL 0x3e
-#define LP5523_REG_TEMP_READ 0x3f
-#define LP5523_REG_TEMP_WRITE 0x40
+#define LP5523_REG_STATUS 0x3A
+#define LP5523_REG_RESET 0x3D
#define LP5523_REG_LED_TEST_CTRL 0x41
#define LP5523_REG_LED_TEST_ADC 0x42
-#define LP5523_REG_ENG1_VARIABLE 0x45
-#define LP5523_REG_ENG2_VARIABLE 0x46
-#define LP5523_REG_ENG3_VARIABLE 0x47
-#define LP5523_REG_MASTER_FADER1 0x48
-#define LP5523_REG_MASTER_FADER2 0x49
-#define LP5523_REG_MASTER_FADER3 0x4a
-#define LP5523_REG_CH1_PROG_START 0x4c
-#define LP5523_REG_CH2_PROG_START 0x4d
-#define LP5523_REG_CH3_PROG_START 0x4e
-#define LP5523_REG_PROG_PAGE_SEL 0x4f
+#define LP5523_REG_PROG_PAGE_SEL 0x4F
#define LP5523_REG_PROG_MEM 0x50
-#define LP5523_CMD_LOAD 0x15 /* 00010101 */
-#define LP5523_CMD_RUN 0x2a /* 00101010 */
-#define LP5523_CMD_DISABLED 0x00 /* 00000000 */
-
+/* Bit description in registers */
#define LP5523_ENABLE 0x40
#define LP5523_AUTO_INC 0x40
#define LP5523_PWR_SAVE 0x20
#define LP5523_PWM_PWR_SAVE 0x04
-#define LP5523_CP_1 0x08
-#define LP5523_CP_1_5 0x10
#define LP5523_CP_AUTO 0x18
-#define LP5523_INT_CLK 0x01
#define LP5523_AUTO_CLK 0x02
+
#define LP5523_EN_LEDTEST 0x80
#define LP5523_LEDTEST_DONE 0x80
-
-#define LP5523_DEFAULT_CURRENT 50 /* microAmps */
-#define LP5523_PROGRAM_LENGTH 32 /* in bytes */
-#define LP5523_PROGRAM_PAGES 6
+#define LP5523_RESET 0xFF
#define LP5523_ADC_SHORTCIRC_LIM 80
-
-#define LP5523_LEDS 9
-#define LP5523_ENGINES 3
-
-#define LP5523_ENG_MASK_BASE 0x30 /* 00110000 */
-
-#define LP5523_ENG_STATUS_MASK 0x07 /* 00000111 */
-
-#define LP5523_IRQ_FLAGS IRQF_TRIGGER_FALLING
-
#define LP5523_EXT_CLK_USED 0x08
-#define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led)))
-#define SHIFT_MASK(id) (((id) - 1) * 2)
+/* Memory Page Selection */
+#define LP5523_PAGE_ENG1 0
+#define LP5523_PAGE_ENG2 1
+#define LP5523_PAGE_ENG3 2
+
+/* Program Memory Operations */
+#define LP5523_MODE_ENG1_M 0x30 /* Operation Mode Register */
+#define LP5523_MODE_ENG2_M 0x0C
+#define LP5523_MODE_ENG3_M 0x03
+#define LP5523_LOAD_ENG1 0x10
+#define LP5523_LOAD_ENG2 0x04
+#define LP5523_LOAD_ENG3 0x01
+
+#define LP5523_ENG1_IS_LOADING(mode) \
+ ((mode & LP5523_MODE_ENG1_M) == LP5523_LOAD_ENG1)
+#define LP5523_ENG2_IS_LOADING(mode) \
+ ((mode & LP5523_MODE_ENG2_M) == LP5523_LOAD_ENG2)
+#define LP5523_ENG3_IS_LOADING(mode) \
+ ((mode & LP5523_MODE_ENG3_M) == LP5523_LOAD_ENG3)
+
+#define LP5523_EXEC_ENG1_M 0x30 /* Enable Register */
+#define LP5523_EXEC_ENG2_M 0x0C
+#define LP5523_EXEC_ENG3_M 0x03
+#define LP5523_EXEC_M 0x3F
+#define LP5523_RUN_ENG1 0x20
+#define LP5523_RUN_ENG2 0x08
+#define LP5523_RUN_ENG3 0x02
enum lp5523_chip_id {
LP5523,
LP55231,
};
-struct lp5523_engine {
- int id;
- u8 mode;
- u8 prog_page;
- u8 mux_page;
- u16 led_mux;
- u8 engine_mask;
-};
-
-struct lp5523_led {
- int id;
- u8 chan_nr;
- u8 led_current;
- u8 max_current;
- struct led_classdev cdev;
- struct work_struct brightness_work;
- u8 brightness;
-};
-
-struct lp5523_chip {
- struct mutex lock; /* Serialize control */
- struct i2c_client *client;
- struct lp5523_engine engines[LP5523_ENGINES];
- struct lp5523_led leds[LP5523_LEDS];
- struct lp5523_platform_data *pdata;
- u8 num_channels;
- u8 num_leds;
-};
-
-static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev)
+static inline void lp5523_wait_opmode_done(void)
{
- return container_of(cdev, struct lp5523_led, cdev);
-}
-
-static inline struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
-{
- return container_of(engine, struct lp5523_chip,
- engines[engine->id - 1]);
-}
-
-static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
-{
- return container_of(led, struct lp5523_chip,
- leds[led->id]);
-}
-
-static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
-static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
-static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern);
-
-static void lp5523_led_brightness_work(struct work_struct *work);
-
-static int lp5523_write(struct i2c_client *client, u8 reg, u8 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value);
+ usleep_range(1000, 2000);
}
-static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf)
+static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current)
{
- s32 ret = i2c_smbus_read_byte_data(client, reg);
-
- if (ret < 0)
- return -EIO;
-
- *buf = ret;
- return 0;
+ led->led_current = led_current;
+ lp55xx_write(led->chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
+ led_current);
}
-static int lp5523_detect(struct i2c_client *client)
+static int lp5523_post_init_device(struct lp55xx_chip *chip)
{
int ret;
- u8 buf;
- ret = lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
+ ret = lp55xx_write(chip, LP5523_REG_ENABLE, LP5523_ENABLE);
if (ret)
return ret;
- ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
- if (ret)
- return ret;
- if (buf == 0x40)
- return 0;
- else
- return -ENODEV;
-}
-static int lp5523_configure(struct i2c_client *client)
-{
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- int ret = 0;
- u8 status;
-
- /* one pattern per engine setting led mux start and stop addresses */
- static const u8 pattern[][LP5523_PROGRAM_LENGTH] = {
- { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
- { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
- { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
- };
-
- ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
/* Chip startup time is 500 us, 1 - 2 ms gives some margin */
usleep_range(1000, 2000);
- ret |= lp5523_write(client, LP5523_REG_CONFIG,
+ ret = lp55xx_write(chip, LP5523_REG_CONFIG,
LP5523_AUTO_INC | LP5523_PWR_SAVE |
LP5523_CP_AUTO | LP5523_AUTO_CLK |
LP5523_PWM_PWR_SAVE);
+ if (ret)
+ return ret;
/* turn on all leds */
- ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
- ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
-
- /* hardcode 32 bytes of memory for each engine from program memory */
- ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00);
- ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10);
- ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20);
-
- /* write led mux address space for each channel */
- ret |= lp5523_load_program(&chip->engines[0], pattern[0]);
- ret |= lp5523_load_program(&chip->engines[1], pattern[1]);
- ret |= lp5523_load_program(&chip->engines[2], pattern[2]);
-
- if (ret) {
- dev_err(&client->dev, "could not load mux programs\n");
- return -1;
- }
-
- /* set all engines exec state and mode to run 00101010 */
- ret |= lp5523_write(client, LP5523_REG_ENABLE,
- (LP5523_CMD_RUN | LP5523_ENABLE));
-
- ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN);
-
- if (ret) {
- dev_err(&client->dev, "could not start mux programs\n");
- return -1;
- }
-
- /* Let the programs run for couple of ms and check the engine status */
- usleep_range(3000, 6000);
- lp5523_read(client, LP5523_REG_STATUS, &status);
- status &= LP5523_ENG_STATUS_MASK;
-
- if (status == LP5523_ENG_STATUS_MASK) {
- dev_dbg(&client->dev, "all engines configured\n");
- } else {
- dev_info(&client->dev, "status == %x\n", status);
- dev_err(&client->dev, "cound not configure LED engine\n");
- return -1;
- }
-
- dev_info(&client->dev, "disabling engines\n");
-
- ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+ ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
+ if (ret)
+ return ret;
- return ret;
+ return lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
}
-static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode)
+static void lp5523_load_engine(struct lp55xx_chip *chip)
{
- struct lp5523_chip *chip = engine_to_lp5523(engine);
- struct i2c_client *client = chip->client;
- int ret;
- u8 engine_state;
+ enum lp55xx_engine_index idx = chip->engine_idx;
+ u8 mask[] = {
+ [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M,
+ [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M,
+ [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M,
+ };
- ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state);
- if (ret)
- goto fail;
+ u8 val[] = {
+ [LP55XX_ENGINE_1] = LP5523_LOAD_ENG1,
+ [LP55XX_ENGINE_2] = LP5523_LOAD_ENG2,
+ [LP55XX_ENGINE_3] = LP5523_LOAD_ENG3,
+ };
- engine_state &= ~(engine->engine_mask);
+ u8 page_sel[] = {
+ [LP55XX_ENGINE_1] = LP5523_PAGE_ENG1,
+ [LP55XX_ENGINE_2] = LP5523_PAGE_ENG2,
+ [LP55XX_ENGINE_3] = LP5523_PAGE_ENG3,
+ };
- /* set mode only for this engine */
- mode &= engine->engine_mask;
+ lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]);
- engine_state |= mode;
+ lp5523_wait_opmode_done();
- ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state);
-fail:
- return ret;
+ lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
}
-static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux)
+static void lp5523_stop_engine(struct lp55xx_chip *chip)
{
- struct lp5523_chip *chip = engine_to_lp5523(engine);
- struct i2c_client *client = chip->client;
- int ret = 0;
-
- ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+ lp55xx_write(chip, LP5523_REG_OP_MODE, 0);
+ lp5523_wait_opmode_done();
+}
- ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page);
- ret |= lp5523_write(client, LP5523_REG_PROG_MEM,
- (u8)(mux >> 8));
- ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux));
- engine->led_mux = mux;
+static void lp5523_turn_off_channels(struct lp55xx_chip *chip)
+{
+ int i;
- return ret;
+ for (i = 0; i < LP5523_MAX_LEDS; i++)
+ lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0);
}
-static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern)
+static void lp5523_run_engine(struct lp55xx_chip *chip, bool start)
{
- struct lp5523_chip *chip = engine_to_lp5523(engine);
- struct i2c_client *client = chip->client;
+ int ret;
+ u8 mode;
+ u8 exec;
- int ret = 0;
+ /* stop engine */
+ if (!start) {
+ lp5523_stop_engine(chip);
+ lp5523_turn_off_channels(chip);
+ return;
+ }
- ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+ /*
+ * To run the engine,
+ * operation mode and enable register should updated at the same time
+ */
- ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL,
- engine->prog_page);
- ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM,
- LP5523_PROGRAM_LENGTH, pattern);
+ ret = lp55xx_read(chip, LP5523_REG_OP_MODE, &mode);
+ if (ret)
+ return;
- return ret;
-}
+ ret = lp55xx_read(chip, LP5523_REG_ENABLE, &exec);
+ if (ret)
+ return;
-static int lp5523_run_program(struct lp5523_engine *engine)
-{
- struct lp5523_chip *chip = engine_to_lp5523(engine);
- struct i2c_client *client = chip->client;
- int ret;
+ /* change operation mode to RUN only when each engine is loading */
+ if (LP5523_ENG1_IS_LOADING(mode)) {
+ mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1;
+ exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1;
+ }
- ret = lp5523_write(client, LP5523_REG_ENABLE,
- LP5523_CMD_RUN | LP5523_ENABLE);
- if (ret)
- goto fail;
+ if (LP5523_ENG2_IS_LOADING(mode)) {
+ mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2;
+ exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2;
+ }
- ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN);
-fail:
- return ret;
+ if (LP5523_ENG3_IS_LOADING(mode)) {
+ mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3;
+ exec = (exec & ~LP5523_EXEC_ENG3_M) | LP5523_RUN_ENG3;
+ }
+
+ lp55xx_write(chip, LP5523_REG_OP_MODE, mode);
+ lp5523_wait_opmode_done();
+
+ lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, exec);
}
-static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
+static int lp5523_update_program_memory(struct lp55xx_chip *chip,
+ const u8 *data, size_t size)
{
+ u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
+ unsigned cmd;
+ char c[3];
+ int update_size;
+ int nrchars;
+ int offset = 0;
+ int ret;
int i;
- u16 tmp_mux = 0;
-
- len = min_t(int, len, LP5523_LEDS);
- for (i = 0; i < len; i++) {
- switch (buf[i]) {
- case '1':
- tmp_mux |= (1 << i);
- break;
- case '0':
- break;
- case '\n':
- i = len;
- break;
- default:
- return -1;
- }
- }
- *mux = tmp_mux;
- return 0;
-}
+ /* clear program memory before updating */
+ for (i = 0; i < LP5523_PROGRAM_LENGTH; i++)
+ lp55xx_write(chip, LP5523_REG_PROG_MEM + i, 0);
-static void lp5523_mux_to_array(u16 led_mux, char *array)
-{
- int i, pos = 0;
- for (i = 0; i < LP5523_LEDS; i++)
- pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
+ i = 0;
+ while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) {
+ /* separate sscanfs because length is working only for %s */
+ ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
+ if (ret != 1)
+ goto err;
- array[pos] = '\0';
-}
+ ret = sscanf(c, "%2x", &cmd);
+ if (ret != 1)
+ goto err;
-/*--------------------------------------------------------------*/
-/* Sysfs interface */
-/*--------------------------------------------------------------*/
+ pattern[i] = (u8)cmd;
+ offset += nrchars;
+ i++;
+ }
-static ssize_t show_engine_leds(struct device *dev,
- struct device_attribute *attr,
- char *buf, int nr)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- char mux[LP5523_LEDS + 1];
+ /* Each instruction is 16bit long. Check that length is even */
+ if (i % 2)
+ goto err;
- lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
+ update_size = i;
+ for (i = 0; i < update_size; i++)
+ lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]);
- return sprintf(buf, "%s\n", mux);
-}
+ return 0;
-#define show_leds(nr) \
-static ssize_t show_engine##nr##_leds(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_engine_leds(dev, attr, buf, nr); \
+err:
+ dev_err(&chip->cl->dev, "wrong pattern format\n");
+ return -EINVAL;
}
-show_leds(1)
-show_leds(2)
-show_leds(3)
-static ssize_t store_engine_leds(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len, int nr)
+static void lp5523_firmware_loaded(struct lp55xx_chip *chip)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- u16 mux = 0;
- ssize_t ret;
+ const struct firmware *fw = chip->fw;
- if (lp5523_mux_parse(buf, &mux, len))
- return -EINVAL;
-
- mutex_lock(&chip->lock);
- ret = -EINVAL;
- if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD)
- goto leave;
+ if (fw->size > LP5523_PROGRAM_LENGTH) {
+ dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
+ fw->size);
+ return;
+ }
- if (lp5523_load_mux(&chip->engines[nr - 1], mux))
- goto leave;
+ /*
+ * Program momery sequence
+ * 1) set engine mode to "LOAD"
+ * 2) write firmware data into program memory
+ */
- ret = len;
-leave:
- mutex_unlock(&chip->lock);
- return ret;
+ lp5523_load_engine(chip);
+ lp5523_update_program_memory(chip, fw->data, fw->size);
}
-#define store_leds(nr) \
-static ssize_t store_engine##nr##_leds(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t len) \
-{ \
- return store_engine_leds(dev, attr, buf, len, nr); \
-}
-store_leds(1)
-store_leds(2)
-store_leds(3)
-
static ssize_t lp5523_selftest(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
+ struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+ struct lp55xx_chip *chip = led->chip;
+ struct lp55xx_platform_data *pdata = chip->pdata;
int i, ret, pos = 0;
- int led = 0;
u8 status, adc, vdd;
mutex_lock(&chip->lock);
- ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
if (ret < 0)
goto fail;
/* Check that ext clock is really in use if requested */
- if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT))
+ if (pdata->clock_mode == LP55XX_CLOCK_EXT) {
if ((status & LP5523_EXT_CLK_USED) == 0)
goto fail;
+ }
/* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
- lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL,
- LP5523_EN_LEDTEST | 16);
+ lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL, LP5523_EN_LEDTEST | 16);
usleep_range(3000, 6000); /* ADC conversion time is typically 2.7 ms */
- ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
+ if (ret < 0)
+ goto fail;
+
if (!(status & LP5523_LEDTEST_DONE))
usleep_range(3000, 6000); /* Was not ready. Wait little bit */
- ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd);
+ ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, &vdd);
+ if (ret < 0)
+ goto fail;
+
vdd--; /* There may be some fluctuation in measurement */
- for (i = 0; i < LP5523_LEDS; i++) {
+ for (i = 0; i < LP5523_MAX_LEDS; i++) {
/* Skip non-existing channels */
- if (chip->pdata->led_config[i].led_current == 0)
+ if (pdata->led_config[i].led_current == 0)
continue;
/* Set default current */
- lp5523_write(chip->client,
- LP5523_REG_LED_CURRENT_BASE + i,
- chip->pdata->led_config[i].led_current);
+ lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i,
+ pdata->led_config[i].led_current);
- lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff);
+ lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0xff);
/* let current stabilize 2 - 4ms before measurements start */
usleep_range(2000, 4000);
- lp5523_write(chip->client,
- LP5523_REG_LED_TEST_CTRL,
+ lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL,
LP5523_EN_LEDTEST | i);
/* ADC conversion time is 2.7 ms typically */
usleep_range(3000, 6000);
- ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+ ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
+ if (ret < 0)
+ goto fail;
+
if (!(status & LP5523_LEDTEST_DONE))
usleep_range(3000, 6000);/* Was not ready. Wait. */
- ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc);
+
+ ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, &adc);
+ if (ret < 0)
+ goto fail;
if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
pos += sprintf(buf + pos, "LED %d FAIL\n", i);
- lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00);
+ lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0x00);
/* Restore current */
- lp5523_write(chip->client,
- LP5523_REG_LED_CURRENT_BASE + i,
- chip->leds[led].led_current);
+ lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i,
+ led->led_current);
led++;
}
if (pos == 0)
@@ -516,249 +381,22 @@ release_lock:
return pos;
}
-static void lp5523_set_brightness(struct led_classdev *cdev,
- enum led_brightness brightness)
-{
- struct lp5523_led *led = cdev_to_led(cdev);
-
- led->brightness = (u8)brightness;
-
- schedule_work(&led->brightness_work);
-}
-
static void lp5523_led_brightness_work(struct work_struct *work)
{
- struct lp5523_led *led = container_of(work,
- struct lp5523_led,
+ struct lp55xx_led *led = container_of(work, struct lp55xx_led,
brightness_work);
- struct lp5523_chip *chip = led_to_lp5523(led);
- struct i2c_client *client = chip->client;
+ struct lp55xx_chip *chip = led->chip;
mutex_lock(&chip->lock);
-
- lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+ lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
-
- mutex_unlock(&chip->lock);
-}
-
-static int lp5523_do_store_load(struct lp5523_engine *engine,
- const char *buf, size_t len)
-{
- struct lp5523_chip *chip = engine_to_lp5523(engine);
- struct i2c_client *client = chip->client;
- int ret, nrchars, offset = 0, i = 0;
- char c[3];
- unsigned cmd;
- u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
-
- if (engine->mode != LP5523_CMD_LOAD)
- return -EINVAL;
-
- while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
- /* separate sscanfs because length is working only for %s */
- ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
- ret = sscanf(c, "%2x", &cmd);
- if (ret != 1)
- goto fail;
- pattern[i] = (u8)cmd;
-
- offset += nrchars;
- i++;
- }
-
- /* Each instruction is 16bit long. Check that length is even */
- if (i % 2)
- goto fail;
-
- mutex_lock(&chip->lock);
- ret = lp5523_load_program(engine, pattern);
- mutex_unlock(&chip->lock);
-
- if (ret) {
- dev_err(&client->dev, "failed loading pattern\n");
- return ret;
- }
-
- return len;
-fail:
- dev_err(&client->dev, "wrong pattern format\n");
- return -EINVAL;
-}
-
-static ssize_t store_engine_load(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len, int nr)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- return lp5523_do_store_load(&chip->engines[nr - 1], buf, len);
-}
-
-#define store_load(nr) \
-static ssize_t store_engine##nr##_load(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t len) \
-{ \
- return store_engine_load(dev, attr, buf, len, nr); \
-}
-store_load(1)
-store_load(2)
-store_load(3)
-
-static ssize_t show_engine_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf, int nr)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- switch (chip->engines[nr - 1].mode) {
- case LP5523_CMD_RUN:
- return sprintf(buf, "run\n");
- case LP5523_CMD_LOAD:
- return sprintf(buf, "load\n");
- case LP5523_CMD_DISABLED:
- return sprintf(buf, "disabled\n");
- default:
- return sprintf(buf, "disabled\n");
- }
-}
-
-#define show_mode(nr) \
-static ssize_t show_engine##nr##_mode(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_engine_mode(dev, attr, buf, nr); \
-}
-show_mode(1)
-show_mode(2)
-show_mode(3)
-
-static ssize_t store_engine_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len, int nr)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- struct lp5523_engine *engine = &chip->engines[nr - 1];
- mutex_lock(&chip->lock);
-
- if (!strncmp(buf, "run", 3))
- lp5523_set_mode(engine, LP5523_CMD_RUN);
- else if (!strncmp(buf, "load", 4))
- lp5523_set_mode(engine, LP5523_CMD_LOAD);
- else if (!strncmp(buf, "disabled", 8))
- lp5523_set_mode(engine, LP5523_CMD_DISABLED);
-
- mutex_unlock(&chip->lock);
- return len;
-}
-
-#define store_mode(nr) \
-static ssize_t store_engine##nr##_mode(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t len) \
-{ \
- return store_engine_mode(dev, attr, buf, len, nr); \
-}
-store_mode(1)
-store_mode(2)
-store_mode(3)
-
-static ssize_t show_max_current(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5523_led *led = cdev_to_led(led_cdev);
-
- return sprintf(buf, "%d\n", led->max_current);
-}
-
-static ssize_t show_current(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5523_led *led = cdev_to_led(led_cdev);
-
- return sprintf(buf, "%d\n", led->led_current);
-}
-
-static ssize_t store_current(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lp5523_led *led = cdev_to_led(led_cdev);
- struct lp5523_chip *chip = led_to_lp5523(led);
- ssize_t ret;
- unsigned long curr;
-
- if (strict_strtoul(buf, 0, &curr))
- return -EINVAL;
-
- if (curr > led->max_current)
- return -EINVAL;
-
- mutex_lock(&chip->lock);
- ret = lp5523_write(chip->client,
- LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
- (u8)curr);
mutex_unlock(&chip->lock);
-
- if (ret < 0)
- return ret;
-
- led->led_current = (u8)curr;
-
- return len;
}
-/* led class device attributes */
-static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
-static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
-
-static struct attribute *lp5523_led_attributes[] = {
- &dev_attr_led_current.attr,
- &dev_attr_max_current.attr,
- NULL,
-};
-
-static struct attribute_group lp5523_led_attribute_group = {
- .attrs = lp5523_led_attributes
-};
-
-/* device attributes */
-static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
- show_engine1_mode, store_engine1_mode);
-static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
- show_engine2_mode, store_engine2_mode);
-static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
- show_engine3_mode, store_engine3_mode);
-static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUSR,
- show_engine1_leds, store_engine1_leds);
-static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUSR,
- show_engine2_leds, store_engine2_leds);
-static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUSR,
- show_engine3_leds, store_engine3_leds);
-static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
-static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
-static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
static struct attribute *lp5523_attributes[] = {
- &dev_attr_engine1_mode.attr,
- &dev_attr_engine2_mode.attr,
- &dev_attr_engine3_mode.attr,
&dev_attr_selftest.attr,
- &dev_attr_engine1_load.attr,
- &dev_attr_engine1_leds.attr,
- &dev_attr_engine2_load.attr,
- &dev_attr_engine2_leds.attr,
- &dev_attr_engine3_load.attr,
- &dev_attr_engine3_leds.attr,
NULL,
};
@@ -766,252 +404,91 @@ static const struct attribute_group lp5523_group = {
.attrs = lp5523_attributes,
};
-static int lp5523_register_sysfs(struct i2c_client *client)
-{
- struct device *dev = &client->dev;
- int ret;
-
- ret = sysfs_create_group(&dev->kobj, &lp5523_group);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static void lp5523_unregister_sysfs(struct i2c_client *client)
-{
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- struct device *dev = &client->dev;
- int i;
-
- sysfs_remove_group(&dev->kobj, &lp5523_group);
-
- for (i = 0; i < chip->num_leds; i++)
- sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
- &lp5523_led_attribute_group);
-}
-
-/*--------------------------------------------------------------*/
-/* Set chip operating mode */
-/*--------------------------------------------------------------*/
-static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
-{
- /* if in that mode already do nothing, except for run */
- if (mode == engine->mode && mode != LP5523_CMD_RUN)
- return;
-
- switch (mode) {
- case LP5523_CMD_RUN:
- lp5523_run_program(engine);
- break;
- case LP5523_CMD_LOAD:
- lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
- lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
- break;
- case LP5523_CMD_DISABLED:
- lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
- break;
- default:
- return;
- }
-
- engine->mode = mode;
-}
-
-/*--------------------------------------------------------------*/
-/* Probe, Attach, Remove */
-/*--------------------------------------------------------------*/
-static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
-{
- if (id < 1 || id > LP5523_ENGINES)
- return -1;
- engine->id = id;
- engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
- engine->prog_page = id - 1;
- engine->mux_page = id + 2;
-
- return 0;
-}
+/* Chip specific configurations */
+static struct lp55xx_device_config lp5523_cfg = {
+ .reset = {
+ .addr = LP5523_REG_RESET,
+ .val = LP5523_RESET,
+ },
+ .enable = {
+ .addr = LP5523_REG_ENABLE,
+ .val = LP5523_ENABLE,
+ },
+ .max_channel = LP5523_MAX_LEDS,
+ .post_init_device = lp5523_post_init_device,
+ .brightness_work_fn = lp5523_led_brightness_work,
+ .set_led_current = lp5523_set_led_current,
+ .firmware_cb = lp5523_firmware_loaded,
+ .run_engine = lp5523_run_engine,
+ .dev_attr_group = &lp5523_group,
+};
-static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
- int chan, struct lp5523_platform_data *pdata,
- const char *chip_name)
+static int lp5523_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- char name[32];
- int res;
+ int ret;
+ struct lp55xx_chip *chip;
+ struct lp55xx_led *led;
+ struct lp55xx_platform_data *pdata = client->dev.platform_data;
- if (chan >= LP5523_LEDS)
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data\n");
return -EINVAL;
-
- if (pdata->led_config[chan].led_current) {
- led->led_current = pdata->led_config[chan].led_current;
- led->max_current = pdata->led_config[chan].max_current;
- led->chan_nr = pdata->led_config[chan].chan_nr;
-
- if (led->chan_nr >= LP5523_LEDS) {
- dev_err(dev, "Use channel numbers between 0 and %d\n",
- LP5523_LEDS - 1);
- return -EINVAL;
- }
-
- if (pdata->led_config[chan].name) {
- led->cdev.name = pdata->led_config[chan].name;
- } else {
- snprintf(name, sizeof(name), "%s:channel%d",
- pdata->label ? : chip_name, chan);
- led->cdev.name = name;
- }
-
- led->cdev.brightness_set = lp5523_set_brightness;
- res = led_classdev_register(dev, &led->cdev);
- if (res < 0) {
- dev_err(dev, "couldn't register led on channel %d\n",
- chan);
- return res;
- }
- res = sysfs_create_group(&led->cdev.dev->kobj,
- &lp5523_led_attribute_group);
- if (res < 0) {
- dev_err(dev, "couldn't register current attribute\n");
- led_classdev_unregister(&led->cdev);
- return res;
- }
- } else {
- led->led_current = 0;
}
- return 0;
-}
-
-static int __devinit lp5523_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct lp5523_chip *chip;
- struct lp5523_platform_data *pdata;
- int ret, i, led;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- i2c_set_clientdata(client, chip);
- chip->client = client;
+ led = devm_kzalloc(&client->dev,
+ sizeof(*led) * pdata->num_channels, GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
- pdata = client->dev.platform_data;
-
- if (!pdata) {
- dev_err(&client->dev, "no platform data\n");
- return -EINVAL;
- }
+ chip->cl = client;
+ chip->pdata = pdata;
+ chip->cfg = &lp5523_cfg;
mutex_init(&chip->lock);
- chip->pdata = pdata;
-
- if (pdata->setup_resources) {
- ret = pdata->setup_resources();
- if (ret < 0)
- return ret;
- }
+ i2c_set_clientdata(client, led);
- if (pdata->enable) {
- pdata->enable(0);
- usleep_range(1000, 2000); /* Keep enable down at least 1ms */
- pdata->enable(1);
- usleep_range(1000, 2000); /* 500us abs min. */
- }
-
- lp5523_write(client, LP5523_REG_RESET, 0xff);
- usleep_range(10000, 20000); /*
- * Exact value is not available. 10 - 20ms
- * appears to be enough for reset.
- */
- ret = lp5523_detect(client);
+ ret = lp55xx_init_device(chip);
if (ret)
- goto fail1;
+ goto err_init;
dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
- /* Initialize engines */
- for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
- ret = lp5523_init_engine(&chip->engines[i], i + 1);
- if (ret) {
- dev_err(&client->dev, "error initializing engine\n");
- goto fail1;
- }
- }
- ret = lp5523_configure(client);
- if (ret < 0) {
- dev_err(&client->dev, "error configuring chip\n");
- goto fail1;
- }
-
- /* Initialize leds */
- chip->num_channels = pdata->num_channels;
- chip->num_leds = 0;
- led = 0;
- for (i = 0; i < pdata->num_channels; i++) {
- /* Do not initialize channels that are not connected */
- if (pdata->led_config[i].led_current == 0)
- continue;
-
- INIT_WORK(&chip->leds[led].brightness_work,
- lp5523_led_brightness_work);
-
- ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata,
- id->name);
- if (ret) {
- dev_err(&client->dev, "error initializing leds\n");
- goto fail2;
- }
- chip->num_leds++;
-
- chip->leds[led].id = led;
- /* Set LED current */
- lp5523_write(client,
- LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
- chip->leds[led].led_current);
-
- led++;
- }
+ ret = lp55xx_register_leds(led, chip);
+ if (ret)
+ goto err_register_leds;
- ret = lp5523_register_sysfs(client);
+ ret = lp55xx_register_sysfs(chip);
if (ret) {
dev_err(&client->dev, "registering sysfs failed\n");
- goto fail2;
+ goto err_register_sysfs;
}
- return ret;
-fail2:
- for (i = 0; i < chip->num_leds; i++) {
- led_classdev_unregister(&chip->leds[i].cdev);
- flush_work(&chip->leds[i].brightness_work);
- }
-fail1:
- if (pdata->enable)
- pdata->enable(0);
- if (pdata->release_resources)
- pdata->release_resources();
+
+ return 0;
+
+err_register_sysfs:
+ lp55xx_unregister_leds(led, chip);
+err_register_leds:
+ lp55xx_deinit_device(chip);
+err_init:
return ret;
}
static int lp5523_remove(struct i2c_client *client)
{
- struct lp5523_chip *chip = i2c_get_clientdata(client);
- int i;
-
- /* Disable engine mode */
- lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+ struct lp55xx_led *led = i2c_get_clientdata(client);
+ struct lp55xx_chip *chip = led->chip;
- lp5523_unregister_sysfs(client);
-
- for (i = 0; i < chip->num_leds; i++) {
- led_classdev_unregister(&chip->leds[i].cdev);
- flush_work(&chip->leds[i].brightness_work);
- }
+ lp5523_stop_engine(chip);
+ lp55xx_unregister_sysfs(chip);
+ lp55xx_unregister_leds(led, chip);
+ lp55xx_deinit_device(chip);
- if (chip->pdata->enable)
- chip->pdata->enable(0);
- if (chip->pdata->release_resources)
- chip->pdata->release_resources();
return 0;
}
@@ -1035,5 +512,6 @@ static struct i2c_driver lp5523_driver = {
module_i2c_driver(lp5523_driver);
MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
MODULE_DESCRIPTION("LP5523 LED engine");
MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
new file mode 100644
index 000000000000..d9eb84157423
--- /dev/null
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -0,0 +1,523 @@
+/*
+ * LP5521/LP5523/LP55231 Common Driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Derived from leds-lp5521.c, leds-lp5523.c
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_data/leds-lp55xx.h>
+
+#include "leds-lp55xx-common.h"
+
+static struct lp55xx_led *cdev_to_lp55xx_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct lp55xx_led, cdev);
+}
+
+static struct lp55xx_led *dev_to_lp55xx_led(struct device *dev)
+{
+ return cdev_to_lp55xx_led(dev_get_drvdata(dev));
+}
+
+static void lp55xx_reset_device(struct lp55xx_chip *chip)
+{
+ struct lp55xx_device_config *cfg = chip->cfg;
+ u8 addr = cfg->reset.addr;
+ u8 val = cfg->reset.val;
+
+ /* no error checking here because no ACK from the device after reset */
+ lp55xx_write(chip, addr, val);
+}
+
+static int lp55xx_detect_device(struct lp55xx_chip *chip)
+{
+ struct lp55xx_device_config *cfg = chip->cfg;
+ u8 addr = cfg->enable.addr;
+ u8 val = cfg->enable.val;
+ int ret;
+
+ ret = lp55xx_write(chip, addr, val);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = lp55xx_read(chip, addr, &val);
+ if (ret)
+ return ret;
+
+ if (val != cfg->enable.val)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int lp55xx_post_init_device(struct lp55xx_chip *chip)
+{
+ struct lp55xx_device_config *cfg = chip->cfg;
+
+ if (!cfg->post_init_device)
+ return 0;
+
+ return cfg->post_init_device(chip);
+}
+
+static ssize_t lp55xx_show_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp55xx_led *led = dev_to_lp55xx_led(dev);
+
+ return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t lp55xx_store_current(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp55xx_led *led = dev_to_lp55xx_led(dev);
+ struct lp55xx_chip *chip = led->chip;
+ unsigned long curr;
+
+ if (kstrtoul(buf, 0, &curr))
+ return -EINVAL;
+
+ if (curr > led->max_current)
+ return -EINVAL;
+
+ if (!chip->cfg->set_led_current)
+ return len;
+
+ mutex_lock(&chip->lock);
+ chip->cfg->set_led_current(led, (u8)curr);
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static ssize_t lp55xx_show_max_current(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp55xx_led *led = dev_to_lp55xx_led(dev);
+
+ return sprintf(buf, "%d\n", led->max_current);
+}
+
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, lp55xx_show_current,
+ lp55xx_store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , lp55xx_show_max_current, NULL);
+
+static struct attribute *lp55xx_led_attributes[] = {
+ &dev_attr_led_current.attr,
+ &dev_attr_max_current.attr,
+ NULL,
+};
+
+static struct attribute_group lp55xx_led_attr_group = {
+ .attrs = lp55xx_led_attributes
+};
+
+static void lp55xx_set_brightness(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lp55xx_led *led = cdev_to_lp55xx_led(cdev);
+
+ led->brightness = (u8)brightness;
+ schedule_work(&led->brightness_work);
+}
+
+static int lp55xx_init_led(struct lp55xx_led *led,
+ struct lp55xx_chip *chip, int chan)
+{
+ struct lp55xx_platform_data *pdata = chip->pdata;
+ struct lp55xx_device_config *cfg = chip->cfg;
+ struct device *dev = &chip->cl->dev;
+ char name[32];
+ int ret;
+ int max_channel = cfg->max_channel;
+
+ if (chan >= max_channel) {
+ dev_err(dev, "invalid channel: %d / %d\n", chan, max_channel);
+ return -EINVAL;
+ }
+
+ if (pdata->led_config[chan].led_current == 0)
+ return 0;
+
+ led->led_current = pdata->led_config[chan].led_current;
+ led->max_current = pdata->led_config[chan].max_current;
+ led->chan_nr = pdata->led_config[chan].chan_nr;
+
+ if (led->chan_nr >= max_channel) {
+ dev_err(dev, "Use channel numbers between 0 and %d\n",
+ max_channel - 1);
+ return -EINVAL;
+ }
+
+ led->cdev.brightness_set = lp55xx_set_brightness;
+
+ if (pdata->led_config[chan].name) {
+ led->cdev.name = pdata->led_config[chan].name;
+ } else {
+ snprintf(name, sizeof(name), "%s:channel%d",
+ pdata->label ? : chip->cl->name, chan);
+ led->cdev.name = name;
+ }
+
+ /*
+ * register led class device for each channel and
+ * add device attributes
+ */
+
+ ret = led_classdev_register(dev, &led->cdev);
+ if (ret) {
+ dev_err(dev, "led register err: %d\n", ret);
+ return ret;
+ }
+
+ ret = sysfs_create_group(&led->cdev.dev->kobj, &lp55xx_led_attr_group);
+ if (ret) {
+ dev_err(dev, "led sysfs err: %d\n", ret);
+ led_classdev_unregister(&led->cdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
+{
+ struct lp55xx_chip *chip = context;
+ struct device *dev = &chip->cl->dev;
+
+ if (!fw) {
+ dev_err(dev, "firmware request failed\n");
+ goto out;
+ }
+
+ /* handling firmware data is chip dependent */
+ mutex_lock(&chip->lock);
+
+ chip->fw = fw;
+ if (chip->cfg->firmware_cb)
+ chip->cfg->firmware_cb(chip);
+
+ mutex_unlock(&chip->lock);
+
+out:
+ /* firmware should be released for other channel use */
+ release_firmware(chip->fw);
+}
+
+static int lp55xx_request_firmware(struct lp55xx_chip *chip)
+{
+ const char *name = chip->cl->name;
+ struct device *dev = &chip->cl->dev;
+
+ return request_firmware_nowait(THIS_MODULE, true, name, dev,
+ GFP_KERNEL, chip, lp55xx_firmware_loaded);
+}
+
+static ssize_t lp55xx_show_engine_select(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+ struct lp55xx_chip *chip = led->chip;
+
+ return sprintf(buf, "%d\n", chip->engine_idx);
+}
+
+static ssize_t lp55xx_store_engine_select(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+ struct lp55xx_chip *chip = led->chip;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ /* select the engine to be run */
+
+ switch (val) {
+ case LP55XX_ENGINE_1:
+ case LP55XX_ENGINE_2:
+ case LP55XX_ENGINE_3:
+ mutex_lock(&chip->lock);
+ chip->engine_idx = val;
+ ret = lp55xx_request_firmware(chip);
+ mutex_unlock(&chip->lock);
+ break;
+ default:
+ dev_err(dev, "%lu: invalid engine index. (1, 2, 3)\n", val);
+ return -EINVAL;
+ }
+
+ if (ret) {
+ dev_err(dev, "request firmware err: %d\n", ret);
+ return ret;
+ }
+
+ return len;
+}
+
+static inline void lp55xx_run_engine(struct lp55xx_chip *chip, bool start)
+{
+ if (chip->cfg->run_engine)
+ chip->cfg->run_engine(chip, start);
+}
+
+static ssize_t lp55xx_store_engine_run(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+ struct lp55xx_chip *chip = led->chip;
+ unsigned long val;
+
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ /* run or stop the selected engine */
+
+ if (val <= 0) {
+ lp55xx_run_engine(chip, false);
+ return len;
+ }
+
+ mutex_lock(&chip->lock);
+ lp55xx_run_engine(chip, true);
+ mutex_unlock(&chip->lock);
+
+ return len;
+}
+
+static DEVICE_ATTR(select_engine, S_IRUGO | S_IWUSR,
+ lp55xx_show_engine_select, lp55xx_store_engine_select);
+static DEVICE_ATTR(run_engine, S_IWUSR, NULL, lp55xx_store_engine_run);
+
+static struct attribute *lp55xx_engine_attributes[] = {
+ &dev_attr_select_engine.attr,
+ &dev_attr_run_engine.attr,
+ NULL,
+};
+
+static const struct attribute_group lp55xx_engine_attr_group = {
+ .attrs = lp55xx_engine_attributes,
+};
+
+int lp55xx_write(struct lp55xx_chip *chip, u8 reg, u8 val)
+{
+ return i2c_smbus_write_byte_data(chip->cl, reg, val);
+}
+EXPORT_SYMBOL_GPL(lp55xx_write);
+
+int lp55xx_read(struct lp55xx_chip *chip, u8 reg, u8 *val)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_byte_data(chip->cl, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lp55xx_read);
+
+int lp55xx_update_bits(struct lp55xx_chip *chip, u8 reg, u8 mask, u8 val)
+{
+ int ret;
+ u8 tmp;
+
+ ret = lp55xx_read(chip, reg, &tmp);
+ if (ret)
+ return ret;
+
+ tmp &= ~mask;
+ tmp |= val & mask;
+
+ return lp55xx_write(chip, reg, tmp);
+}
+EXPORT_SYMBOL_GPL(lp55xx_update_bits);
+
+int lp55xx_init_device(struct lp55xx_chip *chip)
+{
+ struct lp55xx_platform_data *pdata;
+ struct lp55xx_device_config *cfg;
+ struct device *dev = &chip->cl->dev;
+ int ret = 0;
+
+ WARN_ON(!chip);
+
+ pdata = chip->pdata;
+ cfg = chip->cfg;
+
+ if (!pdata || !cfg)
+ return -EINVAL;
+
+ if (pdata->setup_resources) {
+ ret = pdata->setup_resources();
+ if (ret < 0) {
+ dev_err(dev, "setup resoure err: %d\n", ret);
+ goto err;
+ }
+ }
+
+ if (pdata->enable) {
+ pdata->enable(0);
+ usleep_range(1000, 2000); /* Keep enable down at least 1ms */
+ pdata->enable(1);
+ usleep_range(1000, 2000); /* 500us abs min. */
+ }
+
+ lp55xx_reset_device(chip);
+
+ /*
+ * Exact value is not available. 10 - 20ms
+ * appears to be enough for reset.
+ */
+ usleep_range(10000, 20000);
+
+ ret = lp55xx_detect_device(chip);
+ if (ret) {
+ dev_err(dev, "device detection err: %d\n", ret);
+ goto err;
+ }
+
+ /* chip specific initialization */
+ ret = lp55xx_post_init_device(chip);
+ if (ret) {
+ dev_err(dev, "post init device err: %d\n", ret);
+ goto err_post_init;
+ }
+
+ return 0;
+
+err_post_init:
+ lp55xx_deinit_device(chip);
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(lp55xx_init_device);
+
+void lp55xx_deinit_device(struct lp55xx_chip *chip)
+{
+ struct lp55xx_platform_data *pdata = chip->pdata;
+
+ if (pdata->enable)
+ pdata->enable(0);
+
+ if (pdata->release_resources)
+ pdata->release_resources();
+}
+EXPORT_SYMBOL_GPL(lp55xx_deinit_device);
+
+int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
+{
+ struct lp55xx_platform_data *pdata = chip->pdata;
+ struct lp55xx_device_config *cfg = chip->cfg;
+ int num_channels = pdata->num_channels;
+ struct lp55xx_led *each;
+ u8 led_current;
+ int ret;
+ int i;
+
+ if (!cfg->brightness_work_fn) {
+ dev_err(&chip->cl->dev, "empty brightness configuration\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_channels; i++) {
+
+ /* do not initialize channels that are not connected */
+ if (pdata->led_config[i].led_current == 0)
+ continue;
+
+ led_current = pdata->led_config[i].led_current;
+ each = led + i;
+ ret = lp55xx_init_led(each, chip, i);
+ if (ret)
+ goto err_init_led;
+
+ INIT_WORK(&each->brightness_work, cfg->brightness_work_fn);
+
+ chip->num_leds++;
+ each->chip = chip;
+
+ /* setting led current at each channel */
+ if (cfg->set_led_current)
+ cfg->set_led_current(each, led_current);
+ }
+
+ return 0;
+
+err_init_led:
+ lp55xx_unregister_leds(led, chip);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(lp55xx_register_leds);
+
+void lp55xx_unregister_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
+{
+ int i;
+ struct lp55xx_led *each;
+
+ for (i = 0; i < chip->num_leds; i++) {
+ each = led + i;
+ led_classdev_unregister(&each->cdev);
+ flush_work(&each->brightness_work);
+ }
+}
+EXPORT_SYMBOL_GPL(lp55xx_unregister_leds);
+
+int lp55xx_register_sysfs(struct lp55xx_chip *chip)
+{
+ struct device *dev = &chip->cl->dev;
+ struct lp55xx_device_config *cfg = chip->cfg;
+ int ret;
+
+ if (!cfg->run_engine || !cfg->firmware_cb)
+ goto dev_specific_attrs;
+
+ ret = sysfs_create_group(&dev->kobj, &lp55xx_engine_attr_group);
+ if (ret)
+ return ret;
+
+dev_specific_attrs:
+ return cfg->dev_attr_group ?
+ sysfs_create_group(&dev->kobj, cfg->dev_attr_group) : 0;
+}
+EXPORT_SYMBOL_GPL(lp55xx_register_sysfs);
+
+void lp55xx_unregister_sysfs(struct lp55xx_chip *chip)
+{
+ struct device *dev = &chip->cl->dev;
+ struct lp55xx_device_config *cfg = chip->cfg;
+
+ if (cfg->dev_attr_group)
+ sysfs_remove_group(&dev->kobj, cfg->dev_attr_group);
+
+ sysfs_remove_group(&dev->kobj, &lp55xx_engine_attr_group);
+}
+EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs);
+
+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
new file mode 100644
index 000000000000..ece4761a1302
--- /dev/null
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -0,0 +1,134 @@
+/*
+ * LP55XX Common Driver Header
+ *
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Derived from leds-lp5521.c, leds-lp5523.c
+ */
+
+#ifndef _LEDS_LP55XX_COMMON_H
+#define _LEDS_LP55XX_COMMON_H
+
+enum lp55xx_engine_index {
+ LP55XX_ENGINE_INVALID,
+ LP55XX_ENGINE_1,
+ LP55XX_ENGINE_2,
+ LP55XX_ENGINE_3,
+};
+
+struct lp55xx_led;
+struct lp55xx_chip;
+
+/*
+ * struct lp55xx_reg
+ * @addr : Register address
+ * @val : Register value
+ */
+struct lp55xx_reg {
+ u8 addr;
+ u8 val;
+};
+
+/*
+ * struct lp55xx_device_config
+ * @reset : Chip specific reset command
+ * @enable : Chip specific enable command
+ * @max_channel : Maximum number of channels
+ * @post_init_device : Chip specific initialization code
+ * @brightness_work_fn : Brightness work function
+ * @set_led_current : LED current set function
+ * @firmware_cb : Call function when the firmware is loaded
+ * @run_engine : Run internal engine for pattern
+ * @dev_attr_group : Device specific attributes
+ */
+struct lp55xx_device_config {
+ const struct lp55xx_reg reset;
+ const struct lp55xx_reg enable;
+ const int max_channel;
+
+ /* define if the device has specific initialization process */
+ int (*post_init_device) (struct lp55xx_chip *chip);
+
+ /* access brightness register */
+ void (*brightness_work_fn)(struct work_struct *work);
+
+ /* current setting function */
+ void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
+
+ /* access program memory when the firmware is loaded */
+ void (*firmware_cb)(struct lp55xx_chip *chip);
+
+ /* used for running firmware LED patterns */
+ void (*run_engine) (struct lp55xx_chip *chip, bool start);
+
+ /* additional device specific attributes */
+ const struct attribute_group *dev_attr_group;
+};
+
+/*
+ * struct lp55xx_chip
+ * @cl : I2C communication for access registers
+ * @pdata : Platform specific data
+ * @lock : Lock for user-space interface
+ * @num_leds : Number of registered LEDs
+ * @cfg : Device specific configuration data
+ * @engine_idx : Selected engine number
+ * @fw : Firmware data for running a LED pattern
+ */
+struct lp55xx_chip {
+ struct i2c_client *cl;
+ struct lp55xx_platform_data *pdata;
+ struct mutex lock; /* lock for user-space interface */
+ int num_leds;
+ struct lp55xx_device_config *cfg;
+ enum lp55xx_engine_index engine_idx;
+ const struct firmware *fw;
+};
+
+/*
+ * struct lp55xx_led
+ * @chan_nr : Channel number
+ * @cdev : LED class device
+ * @led_current : Current setting at each led channel
+ * @max_current : Maximun current at each led channel
+ * @brightness_work : Workqueue for brightness control
+ * @brightness : Brightness value
+ * @chip : The lp55xx chip data
+ */
+struct lp55xx_led {
+ int chan_nr;
+ struct led_classdev cdev;
+ u8 led_current;
+ u8 max_current;
+ struct work_struct brightness_work;
+ u8 brightness;
+ struct lp55xx_chip *chip;
+};
+
+/* register access */
+extern int lp55xx_write(struct lp55xx_chip *chip, u8 reg, u8 val);
+extern int lp55xx_read(struct lp55xx_chip *chip, u8 reg, u8 *val);
+extern int lp55xx_update_bits(struct lp55xx_chip *chip, u8 reg,
+ u8 mask, u8 val);
+
+/* common device init/deinit functions */
+extern int lp55xx_init_device(struct lp55xx_chip *chip);
+extern void lp55xx_deinit_device(struct lp55xx_chip *chip);
+
+/* common LED class device functions */
+extern int lp55xx_register_leds(struct lp55xx_led *led,
+ struct lp55xx_chip *chip);
+extern void lp55xx_unregister_leds(struct lp55xx_led *led,
+ struct lp55xx_chip *chip);
+
+/* common device attributes functions */
+extern int lp55xx_register_sysfs(struct lp55xx_chip *chip);
+extern void lp55xx_unregister_sysfs(struct lp55xx_chip *chip);
+
+#endif /* _LEDS_LP55XX_COMMON_H */
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 64009a176651..7c2cb384e7ae 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -125,14 +125,15 @@ static void lp8788_brightness_set(struct led_classdev *led_cdev,
schedule_work(&led->work);
}
-static __devinit int lp8788_led_probe(struct platform_device *pdev)
+static int lp8788_led_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct lp8788_led_platform_data *led_pdata;
struct lp8788_led *led;
+ struct device *dev = &pdev->dev;
int ret;
- led = devm_kzalloc(lp->dev, sizeof(struct lp8788_led), GFP_KERNEL);
+ led = devm_kzalloc(dev, sizeof(struct lp8788_led), GFP_KERNEL);
if (!led)
return -ENOMEM;
@@ -154,20 +155,20 @@ static __devinit int lp8788_led_probe(struct platform_device *pdev)
ret = lp8788_led_init_device(led, led_pdata);
if (ret) {
- dev_err(lp->dev, "led init device err: %d\n", ret);
+ dev_err(dev, "led init device err: %d\n", ret);
return ret;
}
- ret = led_classdev_register(lp->dev, &led->led_dev);
+ ret = led_classdev_register(dev, &led->led_dev);
if (ret) {
- dev_err(lp->dev, "led register err: %d\n", ret);
+ dev_err(dev, "led register err: %d\n", ret);
return ret;
}
return 0;
}
-static int __devexit lp8788_led_remove(struct platform_device *pdev)
+static int lp8788_led_remove(struct platform_device *pdev)
{
struct lp8788_led *led = platform_get_drvdata(pdev);
@@ -179,7 +180,7 @@ static int __devexit lp8788_led_remove(struct platform_device *pdev)
static struct platform_driver lp8788_led_driver = {
.probe = lp8788_led_probe,
- .remove = __devexit_p(lp8788_led_remove),
+ .remove = lp8788_led_remove,
.driver = {
.name = LP8788_DEV_KEYLED,
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 09a732217f6d..c9b9e1fec587 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -82,22 +82,18 @@ static void lt3593_led_set(struct led_classdev *led_cdev,
schedule_work(&led_dat->work);
}
-static int __devinit create_lt3593_led(const struct gpio_led *template,
+static int create_lt3593_led(const struct gpio_led *template,
struct lt3593_led_data *led_dat, struct device *parent)
{
int ret, state;
/* skip leds on GPIOs that aren't available */
if (!gpio_is_valid(template->gpio)) {
- printk(KERN_INFO "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
+ dev_info(parent, "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
KBUILD_MODNAME, template->gpio, template->name);
return 0;
}
- ret = gpio_request(template->gpio, template->name);
- if (ret < 0)
- return ret;
-
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
@@ -110,24 +106,21 @@ static int __devinit create_lt3593_led(const struct gpio_led *template,
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, state);
+ ret = devm_gpio_request_one(parent, template->gpio,
+ GPIOF_DIR_OUT | state, template->name);
if (ret < 0)
- goto err;
+ return ret;
INIT_WORK(&led_dat->work, lt3593_led_work);
ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < 0)
- goto err;
+ return ret;
- printk(KERN_INFO "%s: registered LT3593 LED '%s' at GPIO %d\n",
+ dev_info(parent, "%s: registered LT3593 LED '%s' at GPIO %d\n",
KBUILD_MODNAME, template->name, template->gpio);
return 0;
-
-err:
- gpio_free(led_dat->gpio);
- return ret;
}
static void delete_lt3593_led(struct lt3593_led_data *led)
@@ -137,10 +130,9 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
- gpio_free(led->gpio);
}
-static int __devinit lt3593_led_probe(struct platform_device *pdev)
+static int lt3593_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct lt3593_led_data *leds_data;
@@ -173,7 +165,7 @@ err:
return ret;
}
-static int __devexit lt3593_led_remove(struct platform_device *pdev)
+static int lt3593_led_remove(struct platform_device *pdev)
{
int i;
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
@@ -189,7 +181,7 @@ static int __devexit lt3593_led_remove(struct platform_device *pdev)
static struct platform_driver lt3593_led_driver = {
.probe = lt3593_led_probe,
- .remove = __devexit_p(lt3593_led_remove),
+ .remove = lt3593_led_remove,
.driver = {
.name = "leds-lt3593",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 569e36de37df..f449a8bdddc7 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -229,7 +229,7 @@ static ssize_t max8997_led_store_mode(struct device *dev,
static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
-static int __devinit max8997_led_probe(struct platform_device *pdev)
+static int max8997_led_probe(struct platform_device *pdev)
{
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
@@ -292,7 +292,7 @@ static int __devinit max8997_led_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit max8997_led_remove(struct platform_device *pdev)
+static int max8997_led_remove(struct platform_device *pdev)
{
struct max8997_led *led = platform_get_drvdata(pdev);
@@ -308,7 +308,7 @@ static struct platform_driver max8997_led_driver = {
.owner = THIS_MODULE,
},
.probe = max8997_led_probe,
- .remove = __devexit_p(max8997_led_remove),
+ .remove = max8997_led_remove,
};
module_platform_driver(max8997_led_driver);
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 2a5d43400677..e942adaa7504 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -128,7 +128,7 @@ static void mc13783_led_set(struct led_classdev *led_cdev,
schedule_work(&led->work);
}
-static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
+static int mc13783_led_setup(struct mc13783_led *led, int max_current)
{
int shift = 0;
int mask = 0;
@@ -181,7 +181,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
return ret;
}
-static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
+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);
@@ -262,7 +262,7 @@ out:
return ret;
}
-static int __devinit mc13783_led_probe(struct platform_device *pdev)
+static int mc13783_led_probe(struct platform_device *pdev)
{
struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13xxx_led_platform_data *led_cur;
@@ -348,7 +348,7 @@ err_register:
return ret;
}
-static int __devexit mc13783_led_remove(struct platform_device *pdev)
+static int mc13783_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);
@@ -381,7 +381,7 @@ static struct platform_driver mc13783_led_driver = {
.owner = THIS_MODULE,
},
.probe = mc13783_led_probe,
- .remove = __devexit_p(mc13783_led_remove),
+ .remove = mc13783_led_remove,
};
module_platform_driver(mc13783_led_driver);
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index f117f7326c5b..27d06c528246 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/err.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/nsc_gpio.h>
#include <linux/scx200_gpio.h>
#include <linux/module.h>
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
index 461bbf9b33fa..c61c5ebcc08e 100644
--- a/drivers/leds/leds-netxbig.c
+++ b/drivers/leds/leds-netxbig.c
@@ -71,7 +71,7 @@ static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
spin_unlock_irqrestore(&gpio_ext_lock, flags);
}
-static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
+static int gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
{
int err;
int i;
@@ -243,7 +243,7 @@ static ssize_t netxbig_led_sata_store(struct device *dev,
int mode_val;
int ret;
- ret = strict_strtoul(buff, 10, &enable);
+ ret = kstrtoul(buff, 10, &enable);
if (ret < 0)
return ret;
@@ -301,7 +301,7 @@ static void delete_netxbig_led(struct netxbig_led_data *led_dat)
led_classdev_unregister(&led_dat->cdev);
}
-static int __devinit
+static int
create_netxbig_led(struct platform_device *pdev,
struct netxbig_led_data *led_dat,
const struct netxbig_led *template)
@@ -352,7 +352,7 @@ create_netxbig_led(struct platform_device *pdev,
return ret;
}
-static int __devinit netxbig_led_probe(struct platform_device *pdev)
+static int netxbig_led_probe(struct platform_device *pdev)
{
struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
struct netxbig_led_data *leds_data;
@@ -389,7 +389,7 @@ err_free_leds:
return ret;
}
-static int __devexit netxbig_led_remove(struct platform_device *pdev)
+static int netxbig_led_remove(struct platform_device *pdev)
{
struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
struct netxbig_led_data *leds_data;
@@ -407,7 +407,7 @@ static int __devexit netxbig_led_remove(struct platform_device *pdev)
static struct platform_driver netxbig_led_driver = {
.probe = netxbig_led_probe,
- .remove = __devexit_p(netxbig_led_remove),
+ .remove = netxbig_led_remove,
.driver = {
.name = "leds-netxbig",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index d176ec83f5d9..d978171c25b4 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -30,6 +30,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_data/leds-kirkwood-ns2.h>
+#include <linux/of_gpio.h>
/*
* The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in
@@ -149,7 +150,7 @@ static ssize_t ns2_led_sata_store(struct device *dev,
unsigned long enable;
enum ns2_led_modes mode;
- ret = strict_strtoul(buff, 10, &enable);
+ ret = kstrtoul(buff, 10, &enable);
if (ret < 0)
return ret;
@@ -184,36 +185,29 @@ static ssize_t ns2_led_sata_show(struct device *dev,
static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
-static int __devinit
+static int
create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
const struct ns2_led *template)
{
int ret;
enum ns2_led_modes mode;
- ret = gpio_request(template->cmd, template->name);
- if (ret == 0) {
- ret = gpio_direction_output(template->cmd,
- gpio_get_value(template->cmd));
- if (ret)
- gpio_free(template->cmd);
- }
+ ret = devm_gpio_request_one(&pdev->dev, template->cmd,
+ GPIOF_DIR_OUT | gpio_get_value(template->cmd),
+ template->name);
if (ret) {
dev_err(&pdev->dev, "%s: failed to setup command GPIO\n",
template->name);
+ return ret;
}
- ret = gpio_request(template->slow, template->name);
- if (ret == 0) {
- ret = gpio_direction_output(template->slow,
- gpio_get_value(template->slow));
- if (ret)
- gpio_free(template->slow);
- }
+ ret = devm_gpio_request_one(&pdev->dev, template->slow,
+ GPIOF_DIR_OUT | gpio_get_value(template->slow),
+ template->name);
if (ret) {
dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n",
template->name);
- goto err_free_cmd;
+ return ret;
}
rwlock_init(&led_dat->rw_lock);
@@ -228,7 +222,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
ret = ns2_led_get_mode(led_dat, &mode);
if (ret < 0)
- goto err_free_slow;
+ return ret;
/* Set LED initial state. */
led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
@@ -237,7 +231,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0)
- goto err_free_slow;
+ return ret;
ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
if (ret < 0)
@@ -247,11 +241,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
err_free_cdev:
led_classdev_unregister(&led_dat->cdev);
-err_free_slow:
- gpio_free(led_dat->slow);
-err_free_cmd:
- gpio_free(led_dat->cmd);
-
return ret;
}
@@ -259,22 +248,90 @@ static void delete_ns2_led(struct ns2_led_data *led_dat)
{
device_remove_file(led_dat->cdev.dev, &dev_attr_sata);
led_classdev_unregister(&led_dat->cdev);
- gpio_free(led_dat->cmd);
- gpio_free(led_dat->slow);
}
-static int __devinit ns2_led_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF_GPIO
+/*
+ * Translate OpenFirmware node properties into platform_data.
+ */
+static int
+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;
+ int num_leds = 0;
+ int i = 0;
+
+ num_leds = of_get_child_count(np);
+ if (!num_leds)
+ return -ENODEV;
+
+ leds = devm_kzalloc(dev, num_leds * sizeof(struct ns2_led),
+ GFP_KERNEL);
+ if (!leds)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ const char *string;
+ int ret;
+
+ ret = of_get_named_gpio(child, "cmd-gpio", 0);
+ if (ret < 0)
+ return ret;
+ leds[i].cmd = ret;
+ ret = of_get_named_gpio(child, "slow-gpio", 0);
+ if (ret < 0)
+ return ret;
+ leds[i].slow = ret;
+ ret = of_property_read_string(child, "label", &string);
+ leds[i].name = (ret == 0) ? string : child->name;
+ ret = of_property_read_string(child, "linux,default-trigger",
+ &string);
+ if (ret == 0)
+ leds[i].default_trigger = string;
+
+ i++;
+ }
+
+ pdata->leds = leds;
+ pdata->num_leds = num_leds;
+
+ return 0;
+}
+
+static const struct of_device_id of_ns2_leds_match[] = {
+ { .compatible = "lacie,ns2-leds", },
+ {},
+};
+#endif /* CONFIG_OF_GPIO */
+
+static int ns2_led_probe(struct platform_device *pdev)
{
struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
struct ns2_led_data *leds_data;
int i;
int ret;
+#ifdef CONFIG_OF_GPIO
+ if (!pdata) {
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct ns2_led_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ ret = ns2_leds_get_of_pdata(&pdev->dev, pdata);
+ if (ret)
+ return ret;
+ }
+#else
if (!pdata)
return -EINVAL;
+#endif /* CONFIG_OF_GPIO */
leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) *
- pdata->num_leds, GFP_KERNEL);
+ pdata->num_leds, GFP_KERNEL);
if (!leds_data)
return -ENOMEM;
@@ -292,7 +349,7 @@ static int __devinit ns2_led_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit ns2_led_remove(struct platform_device *pdev)
+static int ns2_led_remove(struct platform_device *pdev)
{
int i;
struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
@@ -310,10 +367,11 @@ static int __devexit ns2_led_remove(struct platform_device *pdev)
static struct platform_driver ns2_led_driver = {
.probe = ns2_led_probe,
- .remove = __devexit_p(ns2_led_remove),
+ .remove = ns2_led_remove,
.driver = {
- .name = "leds-ns2",
- .owner = THIS_MODULE,
+ .name = "leds-ns2",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_ns2_leds_match),
},
};
diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c
index c4646825a620..ee14662ed5ce 100644
--- a/drivers/leds/leds-ot200.c
+++ b/drivers/leds/leds-ot200.c
@@ -115,7 +115,7 @@ static void ot200_led_brightness_set(struct led_classdev *led_cdev,
spin_unlock_irqrestore(&value_lock, flags);
}
-static int __devinit ot200_led_probe(struct platform_device *pdev)
+static int ot200_led_probe(struct platform_device *pdev)
{
int i;
int ret;
@@ -144,7 +144,7 @@ err:
return ret;
}
-static int __devexit ot200_led_remove(struct platform_device *pdev)
+static int ot200_led_remove(struct platform_device *pdev)
{
int i;
@@ -156,7 +156,7 @@ static int __devexit ot200_led_remove(struct platform_device *pdev)
static struct platform_driver ot200_led_driver = {
.probe = ot200_led_probe,
- .remove = __devexit_p(ot200_led_remove),
+ .remove = ot200_led_remove,
.driver = {
.name = "leds-ot200",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index cee8a5b483ac..0c597bdd23f9 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -186,7 +186,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
int err = 0;
if (*delay_on == 0 && *delay_off == 0) {
- /* led subsystem ask us for a blink rate */
+ /* led subsystem ask us for a blink rate */
*delay_on = 1000;
*delay_off = 1000;
}
@@ -311,7 +311,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
- input_unregister_device(data->idev);
cancel_work_sync(&data->work);
data->idev = NULL;
}
@@ -382,7 +381,7 @@ static int pca9532_configure(struct i2c_client *client,
BUG_ON(data->idev);
led->state = PCA9532_PWM1;
pca9532_setled(led);
- data->idev = input_allocate_device();
+ data->idev = devm_input_allocate_device(&client->dev);
if (data->idev == NULL) {
err = -ENOMEM;
goto exit;
@@ -401,7 +400,6 @@ static int pca9532_configure(struct i2c_client *client,
INIT_WORK(&data->work, pca9532_input_work);
err = input_register_device(data->idev);
if (err) {
- input_free_device(data->idev);
cancel_work_sync(&data->work);
data->idev = NULL;
goto exit;
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index aef3cf0432fe..edf485b773c8 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -255,7 +255,7 @@ static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness v
schedule_work(&pca955x->work);
}
-static int __devinit pca955x_probe(struct i2c_client *client,
+static int pca955x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca955x *pca955x;
@@ -277,7 +277,7 @@ static int __devinit pca955x_probe(struct i2c_client *client,
return -ENODEV;
}
- printk(KERN_INFO "leds-pca955x: Using %s %d-bit LED driver at "
+ dev_info(&client->dev, "leds-pca955x: Using %s %d-bit LED driver at "
"slave address 0x%02x\n",
id->name, chip->bits, client->addr);
@@ -363,7 +363,7 @@ exit:
return err;
}
-static int __devexit pca955x_remove(struct i2c_client *client)
+static int pca955x_remove(struct i2c_client *client)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
int i;
@@ -382,7 +382,7 @@ static struct i2c_driver pca955x_driver = {
.owner = THIS_MODULE,
},
.probe = pca955x_probe,
- .remove = __devexit_p(pca955x_remove),
+ .remove = pca955x_remove,
.id_table = pca955x_id,
};
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
index 2f2f9c43535d..9aae5679ffb2 100644
--- a/drivers/leds/leds-pca9633.c
+++ b/drivers/leds/leds-pca9633.c
@@ -93,7 +93,7 @@ static void pca9633_led_set(struct led_classdev *led_cdev,
schedule_work(&pca9633->work);
}
-static int __devinit pca9633_probe(struct i2c_client *client,
+static int pca9633_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca9633_led *pca9633;
@@ -164,7 +164,7 @@ exit:
return err;
}
-static int __devexit pca9633_remove(struct i2c_client *client)
+static int pca9633_remove(struct i2c_client *client)
{
struct pca9633_led *pca9633 = i2c_get_clientdata(client);
int i;
@@ -183,7 +183,7 @@ static struct i2c_driver pca9633_driver = {
.owner = THIS_MODULE,
},
.probe = pca9633_probe,
- .remove = __devexit_p(pca9633_remove),
+ .remove = pca9633_remove,
.id_table = pca9633_id,
};
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index f2e44c719437..a1ea5f6a8d39 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include <linux/fb.h>
#include <linux/leds.h>
#include <linux/err.h>
@@ -26,10 +27,15 @@
struct led_pwm_data {
struct led_classdev cdev;
struct pwm_device *pwm;
- unsigned int active_low;
+ unsigned int active_low;
unsigned int period;
};
+struct led_pwm_priv {
+ int num_leds;
+ struct led_pwm_data leds[0];
+};
+
static void led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
@@ -47,88 +53,152 @@ static void led_pwm_set(struct led_classdev *led_cdev,
}
}
-static int led_pwm_probe(struct platform_device *pdev)
+static inline size_t sizeof_pwm_leds_priv(int num_leds)
{
- struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
- struct led_pwm *cur_led;
- struct led_pwm_data *leds_data, *led_dat;
- int i, ret = 0;
+ return sizeof(struct led_pwm_priv) +
+ (sizeof(struct led_pwm_data) * num_leds);
+}
+
+static struct led_pwm_priv *led_pwm_create_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *child;
+ struct led_pwm_priv *priv;
+ int count, ret;
- if (!pdata)
- return -EBUSY;
+ /* count LEDs in this device, so we know how much to allocate */
+ count = of_get_child_count(node);
+ if (!count)
+ return NULL;
- leds_data = devm_kzalloc(&pdev->dev,
- sizeof(struct led_pwm_data) * pdata->num_leds,
- GFP_KERNEL);
- if (!leds_data)
- return -ENOMEM;
+ priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count),
+ GFP_KERNEL);
+ if (!priv)
+ return NULL;
- for (i = 0; i < pdata->num_leds; i++) {
- cur_led = &pdata->leds[i];
- led_dat = &leds_data[i];
+ for_each_child_of_node(node, child) {
+ struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
- led_dat->pwm = pwm_request(cur_led->pwm_id,
- cur_led->name);
+ led_dat->cdev.name = of_get_property(child, "label",
+ NULL) ? : child->name;
+
+ led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL);
if (IS_ERR(led_dat->pwm)) {
- ret = PTR_ERR(led_dat->pwm);
- dev_err(&pdev->dev, "unable to request PWM %d\n",
- cur_led->pwm_id);
+ dev_err(&pdev->dev, "unable to request PWM for %s\n",
+ led_dat->cdev.name);
goto err;
}
+ /* Get the period from PWM core when n*/
+ led_dat->period = pwm_get_period(led_dat->pwm);
+
+ led_dat->cdev.default_trigger = of_get_property(child,
+ "linux,default-trigger", NULL);
+ of_property_read_u32(child, "max-brightness",
+ &led_dat->cdev.max_brightness);
- led_dat->cdev.name = cur_led->name;
- led_dat->cdev.default_trigger = cur_led->default_trigger;
- led_dat->active_low = cur_led->active_low;
- led_dat->period = cur_led->pwm_period_ns;
led_dat->cdev.brightness_set = led_pwm_set;
led_dat->cdev.brightness = LED_OFF;
- led_dat->cdev.max_brightness = cur_led->max_brightness;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0) {
- pwm_free(led_dat->pwm);
+ dev_err(&pdev->dev, "failed to register for %s\n",
+ led_dat->cdev.name);
+ of_node_put(child);
goto err;
}
+ priv->num_leds++;
}
- platform_set_drvdata(pdev, leds_data);
+ return priv;
+err:
+ while (priv->num_leds--)
+ led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
- return 0;
+ return NULL;
+}
-err:
- if (i > 0) {
- for (i = i - 1; i >= 0; i--) {
- led_classdev_unregister(&leds_data[i].cdev);
- pwm_free(leds_data[i].pwm);
+static int led_pwm_probe(struct platform_device *pdev)
+{
+ struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
+ struct led_pwm_priv *priv;
+ int i, ret = 0;
+
+ if (pdata && pdata->num_leds) {
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof_pwm_leds_priv(pdata->num_leds),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ struct led_pwm *cur_led = &pdata->leds[i];
+ struct led_pwm_data *led_dat = &priv->leds[i];
+
+ led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name);
+ if (IS_ERR(led_dat->pwm)) {
+ ret = PTR_ERR(led_dat->pwm);
+ dev_err(&pdev->dev,
+ "unable to request PWM for %s\n",
+ cur_led->name);
+ goto err;
+ }
+
+ led_dat->cdev.name = cur_led->name;
+ led_dat->cdev.default_trigger = cur_led->default_trigger;
+ led_dat->active_low = cur_led->active_low;
+ led_dat->period = cur_led->pwm_period_ns;
+ led_dat->cdev.brightness_set = led_pwm_set;
+ led_dat->cdev.brightness = LED_OFF;
+ led_dat->cdev.max_brightness = cur_led->max_brightness;
+ led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+
+ ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+ if (ret < 0)
+ goto err;
}
+ priv->num_leds = pdata->num_leds;
+ } else {
+ priv = led_pwm_create_of(pdev);
+ if (!priv)
+ return -ENODEV;
}
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+
+err:
+ while (i--)
+ led_classdev_unregister(&priv->leds[i].cdev);
+
return ret;
}
-static int __devexit led_pwm_remove(struct platform_device *pdev)
+static int led_pwm_remove(struct platform_device *pdev)
{
+ struct led_pwm_priv *priv = platform_get_drvdata(pdev);
int i;
- struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
- struct led_pwm_data *leds_data;
- leds_data = platform_get_drvdata(pdev);
-
- for (i = 0; i < pdata->num_leds; i++) {
- led_classdev_unregister(&leds_data[i].cdev);
- pwm_free(leds_data[i].pwm);
- }
+ for (i = 0; i < priv->num_leds; i++)
+ led_classdev_unregister(&priv->leds[i].cdev);
return 0;
}
+static const struct of_device_id of_pwm_leds_match[] = {
+ { .compatible = "pwm-leds", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_leds_match);
+
static struct platform_driver led_pwm_driver = {
.probe = led_pwm_probe,
- .remove = __devexit_p(led_pwm_remove),
+ .remove = led_pwm_remove,
.driver = {
.name = "leds_pwm",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_pwm_leds_match),
},
};
diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c
index a7815b6cd856..2e746d257b02 100644
--- a/drivers/leds/leds-rb532.c
+++ b/drivers/leds/leds-rb532.c
@@ -16,7 +16,7 @@
#include <asm/mach-rc32434/rb.h>
static void rb532_led_set(struct led_classdev *cdev,
- enum led_brightness brightness)
+ enum led_brightness brightness)
{
if (brightness)
set_latch_u5(LO_ULED, 0);
@@ -37,12 +37,12 @@ static struct led_classdev rb532_uled = {
.default_trigger = "nand-disk",
};
-static int __devinit rb532_led_probe(struct platform_device *pdev)
+static int rb532_led_probe(struct platform_device *pdev)
{
return led_classdev_register(&pdev->dev, &rb532_uled);
}
-static int __devexit rb532_led_remove(struct platform_device *pdev)
+static int rb532_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&rb532_uled);
return 0;
@@ -50,7 +50,7 @@ static int __devexit rb532_led_remove(struct platform_device *pdev)
static struct platform_driver rb532_led_driver = {
.probe = rb532_led_probe,
- .remove = __devexit_p(rb532_led_remove),
+ .remove = rb532_led_remove,
.driver = {
.name = "rb532-led",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
index 25d382d60fa9..4253a9b03dbf 100644
--- a/drivers/leds/leds-regulator.c
+++ b/drivers/leds/leds-regulator.c
@@ -140,7 +140,7 @@ static void regulator_led_brightness_set(struct led_classdev *led_cdev,
schedule_work(&led->work);
}
-static int __devinit regulator_led_probe(struct platform_device *pdev)
+static int regulator_led_probe(struct platform_device *pdev)
{
struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
struct regulator_led *led;
@@ -206,7 +206,7 @@ err_vcc:
return ret;
}
-static int __devexit regulator_led_remove(struct platform_device *pdev)
+static int regulator_led_remove(struct platform_device *pdev)
{
struct regulator_led *led = platform_get_drvdata(pdev);
@@ -223,7 +223,7 @@ static struct platform_driver regulator_led_driver = {
.owner = THIS_MODULE,
},
.probe = regulator_led_probe,
- .remove = __devexit_p(regulator_led_remove),
+ .remove = regulator_led_remove,
};
module_platform_driver(regulator_led_driver);
diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
index 771ea067e680..d3c2b7e68fbc 100644
--- a/drivers/leds/leds-renesas-tpu.c
+++ b/drivers/leds/leds-renesas-tpu.c
@@ -133,24 +133,24 @@ static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
rate = clk_get_rate(p->clk);
/* pick the lowest acceptable rate */
- for (k = 0; k < ARRAY_SIZE(prescaler); k++)
- if ((rate / prescaler[k]) < p->min_rate)
+ for (k = ARRAY_SIZE(prescaler) - 1; k >= 0; k--)
+ if ((rate / prescaler[k]) >= p->min_rate)
break;
- if (!k) {
+ if (k < 0) {
dev_err(&p->pdev->dev, "clock rate mismatch\n");
goto err0;
}
dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
- rate, prescaler[k - 1]);
+ rate, prescaler[k]);
/* clear TCNT on TGRB match, count on rising edge, set prescaler */
- r_tpu_write(p, TCR, 0x0040 | (k - 1));
+ r_tpu_write(p, TCR, 0x0040 | k);
/* output 0 until TGRA, output 1 until TGRB */
r_tpu_write(p, TIOR, 0x0002);
- rate /= prescaler[k - 1] * p->refresh_rate;
+ rate /= prescaler[k] * p->refresh_rate;
r_tpu_write(p, TGRB, rate);
dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
@@ -204,10 +204,10 @@ static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
if (p->pin_state == R_TPU_PIN_GPIO_FN)
gpio_free(cfg->pin_gpio_fn);
- if (new_state == R_TPU_PIN_GPIO) {
- gpio_request(cfg->pin_gpio, cfg->name);
- gpio_direction_output(cfg->pin_gpio, !!brightness);
- }
+ if (new_state == R_TPU_PIN_GPIO)
+ gpio_request_one(cfg->pin_gpio, GPIOF_DIR_OUT | !!brightness,
+ cfg->name);
+
if (new_state == R_TPU_PIN_GPIO_FN)
gpio_request(cfg->pin_gpio_fn, cfg->name);
@@ -238,7 +238,7 @@ static void r_tpu_set_brightness(struct led_classdev *ldev,
schedule_work(&p->work);
}
-static int __devinit r_tpu_probe(struct platform_device *pdev)
+static int r_tpu_probe(struct platform_device *pdev)
{
struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
struct r_tpu_priv *p;
@@ -263,18 +263,18 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
}
/* map memory, let mapbase point to our channel */
- p->mapbase = ioremap_nocache(res->start, resource_size(res));
+ p->mapbase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
if (p->mapbase == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
return -ENXIO;
}
/* get hold of clock */
- p->clk = clk_get(&pdev->dev, NULL);
+ p->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(p->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(p->clk);
- goto err0;
+ return PTR_ERR(p->clk);
}
p->pdev = pdev;
@@ -293,7 +293,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
p->ldev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &p->ldev);
if (ret < 0)
- goto err1;
+ goto err0;
/* max_brightness may be updated by the LED core code */
p->min_rate = p->ldev.max_brightness * p->refresh_rate;
@@ -301,15 +301,12 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
- err1:
- r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
- clk_put(p->clk);
err0:
- iounmap(p->mapbase);
+ r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
return ret;
}
-static int __devexit r_tpu_remove(struct platform_device *pdev)
+static int r_tpu_remove(struct platform_device *pdev)
{
struct r_tpu_priv *p = platform_get_drvdata(pdev);
@@ -320,15 +317,13 @@ static int __devexit r_tpu_remove(struct platform_device *pdev)
r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
pm_runtime_disable(&pdev->dev);
- clk_put(p->clk);
- iounmap(p->mapbase);
return 0;
}
static struct platform_driver r_tpu_device_driver = {
.probe = r_tpu_probe,
- .remove = __devexit_p(r_tpu_remove),
+ .remove = r_tpu_remove,
.driver = {
.name = "leds-renesas-tpu",
}
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
index 57371e1485ab..64e204e714f6 100644
--- a/drivers/leds/leds-ss4200.c
+++ b/drivers/leds/leds-ss4200.c
@@ -63,8 +63,7 @@ MODULE_LICENSE("GPL");
/*
* PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
*/
-static const struct pci_device_id ich7_lpc_pci_id[] =
-{
+static DEFINE_PCI_DEVICE_TABLE(ich7_lpc_pci_id) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
@@ -263,7 +262,7 @@ static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
* already taken care of this, but we will do so in a non destructive manner
* so that we have what we need whether the BIOS did it or not.
*/
-static int __devinit ich7_gpio_init(struct device *dev)
+static int ich7_gpio_init(struct device *dev)
{
int i;
u32 config_data = 0;
@@ -342,7 +341,7 @@ static void ich7_lpc_cleanup(struct device *dev)
* so we can retrive the required operational information and prepare the GPIO.
*/
static struct pci_dev *nas_gpio_pci_dev;
-static int __devinit ich7_lpc_probe(struct pci_dev *dev,
+static int ich7_lpc_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
int status;
@@ -459,7 +458,7 @@ static ssize_t nas_led_blink_store(struct device *dev,
struct led_classdev *led = dev_get_drvdata(dev);
unsigned long blink_state;
- ret = strict_strtoul(buf, 10, &blink_state);
+ ret = kstrtoul(buf, 10, &blink_state);
if (ret)
return ret;
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
index 134d9a4b34f1..89792990088d 100644
--- a/drivers/leds/leds-sunfire.c
+++ b/drivers/leds/leds-sunfire.c
@@ -3,6 +3,8 @@
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -14,9 +16,6 @@
#include <asm/fhc.h>
#include <asm/upa.h>
-#define DRIVER_NAME "leds-sunfire"
-#define PFX DRIVER_NAME ": "
-
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_DESCRIPTION("Sun Fire LED driver");
MODULE_LICENSE("GPL");
@@ -123,21 +122,21 @@ struct sunfire_drvdata {
struct sunfire_led leds[NUM_LEDS_PER_BOARD];
};
-static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
+static int sunfire_led_generic_probe(struct platform_device *pdev,
struct led_type *types)
{
struct sunfire_drvdata *p;
int i, err;
if (pdev->num_resources != 1) {
- printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
+ dev_err(&pdev->dev, "Wrong number of resources %d, should be 1\n",
pdev->num_resources);
return -EINVAL;
}
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
+ dev_err(&pdev->dev, "Could not allocate struct sunfire_drvdata\n");
return -ENOMEM;
}
@@ -152,7 +151,7 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
err = led_classdev_register(&pdev->dev, lp);
if (err) {
- printk(KERN_ERR PFX "Could not register %s LED\n",
+ dev_err(&pdev->dev, "Could not register %s LED\n",
lp->name);
for (i--; i >= 0; i--)
led_classdev_unregister(&p->leds[i].led_cdev);
@@ -165,7 +164,7 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
return 0;
}
-static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
+static int sunfire_led_generic_remove(struct platform_device *pdev)
{
struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
int i;
@@ -188,11 +187,11 @@ static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
{
.name = "clockboard-right",
.handler = clockboard_right_set,
- .default_trigger= "heartbeat",
+ .default_trigger = "heartbeat",
},
};
-static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
+static int sunfire_clockboard_led_probe(struct platform_device *pdev)
{
return sunfire_led_generic_probe(pdev, clockboard_led_types);
}
@@ -209,11 +208,11 @@ static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
{
.name = "fhc-right",
.handler = fhc_right_set,
- .default_trigger= "heartbeat",
+ .default_trigger = "heartbeat",
},
};
-static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
+static int sunfire_fhc_led_probe(struct platform_device *pdev)
{
return sunfire_led_generic_probe(pdev, fhc_led_types);
}
@@ -223,7 +222,7 @@ MODULE_ALIAS("platform:sunfire-fhc-leds");
static struct platform_driver sunfire_clockboard_led_driver = {
.probe = sunfire_clockboard_led_probe,
- .remove = __devexit_p(sunfire_led_generic_remove),
+ .remove = sunfire_led_generic_remove,
.driver = {
.name = "sunfire-clockboard-leds",
.owner = THIS_MODULE,
@@ -232,7 +231,7 @@ static struct platform_driver sunfire_clockboard_led_driver = {
static struct platform_driver sunfire_fhc_led_driver = {
.probe = sunfire_fhc_led_probe,
- .remove = __devexit_p(sunfire_led_generic_remove),
+ .remove = sunfire_led_generic_remove,
.driver = {
.name = "sunfire-fhc-leds",
.owner = THIS_MODULE,
@@ -244,13 +243,13 @@ static int __init sunfire_leds_init(void)
int err = platform_driver_register(&sunfire_clockboard_led_driver);
if (err) {
- printk(KERN_ERR PFX "Could not register clock board LED driver\n");
+ pr_err("Could not register clock board LED driver\n");
return err;
}
err = platform_driver_register(&sunfire_fhc_led_driver);
if (err) {
- printk(KERN_ERR PFX "Could not register FHC LED driver\n");
+ pr_err("Could not register FHC LED driver\n");
platform_driver_unregister(&sunfire_clockboard_led_driver);
}
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index dabcf7ae8d0f..070ba0741b21 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -667,8 +667,68 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca)
}
#endif /* CONFIG_GPIOLIB */
-static int __devinit tca6507_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+#ifdef CONFIG_OF
+static struct tca6507_platform_data *
+tca6507_led_dt_init(struct i2c_client *client)
+{
+ struct device_node *np = client->dev.of_node, *child;
+ struct tca6507_platform_data *pdata;
+ struct led_info *tca_leds;
+ int count;
+
+ count = of_get_child_count(np);
+ if (!count || count > NUM_LEDS)
+ return ERR_PTR(-ENODEV);
+
+ tca_leds = devm_kzalloc(&client->dev,
+ sizeof(struct led_info) * count, GFP_KERNEL);
+ if (!tca_leds)
+ return ERR_PTR(-ENOMEM);
+
+ for_each_child_of_node(np, child) {
+ struct led_info led;
+ u32 reg;
+ int ret;
+
+ led.name =
+ of_get_property(child, "label", NULL) ? : child->name;
+ led.default_trigger =
+ of_get_property(child, "linux,default-trigger", NULL);
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret != 0)
+ continue;
+
+ tca_leds[reg] = led;
+ }
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct tca6507_platform_data), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->leds.leds = tca_leds;
+ pdata->leds.num_leds = count;
+
+ return pdata;
+}
+
+static const struct of_device_id of_tca6507_leds_match[] = {
+ { .compatible = "ti,tca6507", },
+ {},
+};
+
+#else
+static struct tca6507_platform_data *
+tca6507_led_dt_init(struct i2c_client *client)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+#define of_tca6507_leds_match NULL
+#endif
+
+static int tca6507_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tca6507_chip *tca;
struct i2c_adapter *adapter;
@@ -683,9 +743,12 @@ static int __devinit tca6507_probe(struct i2c_client *client,
return -EIO;
if (!pdata || pdata->leds.num_leds != NUM_LEDS) {
- dev_err(&client->dev, "Need %d entries in platform-data list\n",
- NUM_LEDS);
- return -ENODEV;
+ pdata = tca6507_led_dt_init(client);
+ if (IS_ERR(pdata)) {
+ dev_err(&client->dev, "Need %d entries in platform-data list\n",
+ NUM_LEDS);
+ return PTR_ERR(pdata);
+ }
}
tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL);
if (!tca)
@@ -730,7 +793,7 @@ exit:
return err;
}
-static int __devexit tca6507_remove(struct i2c_client *client)
+static int tca6507_remove(struct i2c_client *client)
{
int i;
struct tca6507_chip *tca = i2c_get_clientdata(client);
@@ -750,9 +813,10 @@ static struct i2c_driver tca6507_driver = {
.driver = {
.name = "leds-tca6507",
.owner = THIS_MODULE,
+ .of_match_table = of_tca6507_leds_match,
},
.probe = tca6507_probe,
- .remove = __devexit_p(tca6507_remove),
+ .remove = tca6507_remove,
.id_table = tca6507_id,
};
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 74a24cf897c3..6bd5c679d877 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -157,7 +157,7 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev,
return ret;
}
-static const char *led_src_texts[] = {
+static const char * const led_src_texts[] = {
"otp",
"power",
"charger",
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 88f23f845595..ed15157c8f6c 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -216,13 +216,13 @@ static int wm8350_led_probe(struct platform_device *pdev)
isink = devm_regulator_get(&pdev->dev, "led_isink");
if (IS_ERR(isink)) {
- printk(KERN_ERR "%s: can't get ISINK\n", __func__);
+ dev_err(&pdev->dev, "%s: can't get ISINK\n", __func__);
return PTR_ERR(isink);
}
dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
if (IS_ERR(dcdc)) {
- printk(KERN_ERR "%s: can't get DCDC\n", __func__);
+ dev_err(&pdev->dev, "%s: can't get DCDC\n", __func__);
return PTR_ERR(dcdc);
}
diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c
index 6e21e654bb02..b358cc05eff5 100644
--- a/drivers/leds/leds-wrap.c
+++ b/drivers/leds/leds-wrap.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/err.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/scx200_gpio.h>
#include <linux/module.h>
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
index b941685f2227..027a2b15d7d8 100644
--- a/drivers/leds/ledtrig-backlight.c
+++ b/drivers/leds/ledtrig-backlight.c
@@ -40,7 +40,7 @@ static int fb_notifier_callback(struct notifier_block *p,
int new_status = *blank ? BLANK : UNBLANK;
switch (event) {
- case FB_EVENT_BLANK :
+ case FB_EVENT_BLANK:
if (new_status == n->old_status)
break;
@@ -76,7 +76,7 @@ static ssize_t bl_trig_invert_store(struct device *dev,
unsigned long invert;
int ret;
- ret = strict_strtoul(buf, 10, &invert);
+ ret = kstrtoul(buf, 10, &invert);
if (ret < 0)
return ret;
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
index b312056da14d..4239b3955ff0 100644
--- a/drivers/leds/ledtrig-cpu.c
+++ b/drivers/leds/ledtrig-cpu.c
@@ -33,8 +33,6 @@
struct led_trigger_cpu {
char name[MAX_NAME_LEN];
struct led_trigger *_trig;
- struct mutex lock;
- int lock_is_inited;
};
static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
@@ -50,12 +48,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt)
{
struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
- /* mutex lock should be initialized before calling mutex_call() */
- if (!trig->lock_is_inited)
- return;
-
- mutex_lock(&trig->lock);
-
/* Locate the correct CPU LED */
switch (ledevt) {
case CPU_LED_IDLE_END:
@@ -75,8 +67,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt)
/* Will leave the LED as it is */
break;
}
-
- mutex_unlock(&trig->lock);
}
EXPORT_SYMBOL(ledtrig_cpu);
@@ -117,14 +107,9 @@ static int __init ledtrig_cpu_init(void)
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
- mutex_init(&trig->lock);
-
snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
- mutex_lock(&trig->lock);
led_trigger_register_simple(trig->name, &trig->_trig);
- trig->lock_is_inited = 1;
- mutex_unlock(&trig->lock);
}
register_syscore_ops(&ledtrig_cpu_syscore_ops);
@@ -142,15 +127,9 @@ static void __exit ledtrig_cpu_exit(void)
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
- mutex_lock(&trig->lock);
-
led_trigger_unregister_simple(trig->_trig);
trig->_trig = NULL;
memset(trig->name, 0, MAX_NAME_LEN);
- trig->lock_is_inited = 0;
-
- mutex_unlock(&trig->lock);
- mutex_destroy(&trig->lock);
}
unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index ba215dc42f98..72e3ebfc281f 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -110,7 +110,7 @@ static ssize_t gpio_trig_inverted_store(struct device *dev,
unsigned long inverted;
int ret;
- ret = strict_strtoul(buf, 10, &inverted);
+ ret = kstrtoul(buf, 10, &inverted);
if (ret < 0)
return ret;