]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
i2c: lp5521: move to LED framework
authorFelipe Balbi <felipe.balbi@nokia.com>
Fri, 13 Feb 2009 12:43:50 +0000 (14:43 +0200)
committerTony Lindgren <tony@atomide.com>
Tue, 17 Feb 2009 23:34:43 +0000 (15:34 -0800)
Register three separate leds for lp5521 and allow
them to be controlled separately while keeping
backwards compatibility with userspace programs
based on old implementation.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/i2c/chips/lp5521.c
include/linux/i2c/lp5521.h [new file with mode: 0644]

index 9e94ff8b52924e92d744236080f2bed013f46271..b3ba52ab6c452082a9464b7bfc5af6d9111af6fc 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2007 Nokia Corporation
  *
  * Written by Mathias Nyman <mathias.nyman@nokia.com>
+ * Updated by Felipe Balbi <felipe.balbi@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/lp5521.h>
 
 #define LP5521_DRIVER_NAME             "lp5521"
 
 
 #define LP5521_PROGRAM_LENGTH          32      /* in bytes */
 
-enum lp5521_mode {
-       LP5521_MODE_LOAD,
-       LP5521_MODE_RUN,
-       LP5521_MODE_DIRECT_CONTROL,
-};
-
 struct lp5521_chip {
        /* device lock */
        struct mutex            lock;
        struct i2c_client       *client;
+
+       struct work_struct      red_work;
+       struct work_struct      green_work;
+       struct work_struct      blue_work;
+
+       struct led_classdev     ledr;
+       struct led_classdev     ledg;
+       struct led_classdev     ledb;
+
        enum lp5521_mode        mode;
+
        int                     red;
        int                     green;
        int                     blue;
@@ -489,6 +497,87 @@ static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode)
        return ret;
 }
 
+static void lp5521_red_work(struct work_struct *work)
+{
+       struct lp5521_chip *chip = container_of(work, struct lp5521_chip, red_work);
+       int ret;
+
+       ret = lp5521_configure(chip->client);
+       if (ret) {
+               dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n",
+                               ret);
+               return;
+       }
+
+       ret = lp5521_write(chip->client, LP5521_REG_R_PWM, chip->red);
+       if (ret)
+               dev_dbg(&chip->client->dev, "could not set brightness, %d\n",
+                               ret);
+}
+
+static void lp5521_red_set(struct led_classdev *led,
+               enum led_brightness value)
+{
+       struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledr);
+
+       chip->red = value;
+       schedule_work(&chip->red_work);
+}
+
+static void lp5521_green_work(struct work_struct *work)
+{
+       struct lp5521_chip *chip = container_of(work, struct lp5521_chip, green_work);
+       int ret;
+
+       ret = lp5521_configure(chip->client);
+       if (ret) {
+               dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n",
+                               ret);
+               return;
+       }
+
+       ret = lp5521_write(chip->client, LP5521_REG_G_PWM, chip->green);
+       if (ret)
+               dev_dbg(&chip->client->dev, "could not set brightness, %d\n",
+                               ret);
+}
+
+static void lp5521_green_set(struct led_classdev *led,
+               enum led_brightness value)
+{
+       struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledg);
+
+       chip->green = value;
+       schedule_work(&chip->green_work);
+}
+
+static void lp5521_blue_work(struct work_struct *work)
+{
+       struct lp5521_chip *chip = container_of(work, struct lp5521_chip, blue_work);
+       int ret;
+
+       ret = lp5521_configure(chip->client);
+       if (ret) {
+               dev_dbg(&chip->client->dev, "could not configure lp5521, %d\n",
+                               ret);
+               return;
+       }
+
+       ret = lp5521_write(chip->client, LP5521_REG_B_PWM, chip->blue);
+       if (ret)
+               dev_dbg(&chip->client->dev, "could not set brightness, %d\n",
+                               ret);
+}
+
+static void lp5521_blue_set(struct led_classdev *led,
+               enum led_brightness value)
+{
+       struct lp5521_chip *chip = container_of(led, struct lp5521_chip, ledb);
+
+       chip->blue = value;
+       schedule_work(&chip->blue_work);
+}
+
 /*--------------------------------------------------------------*/
 /*                     Probe, Attach, Remove                   */
 /*--------------------------------------------------------------*/
@@ -496,9 +585,16 @@ static int lp5521_set_mode(struct lp5521_chip *chip, enum lp5521_mode mode)
 static int __init lp5521_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
+       struct lp5521_platform_data *pdata = client->dev.platform_data;
        struct lp5521_chip *chip;
+       char name[16];
        int ret = 0;
 
+       if (!pdata) {
+               dev_err(&client->dev, "platform_data is missing\n");
+               return -EINVAL;
+       }
+
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
@@ -509,6 +605,10 @@ static int __init lp5521_probe(struct i2c_client *client,
 
        mutex_init(&chip->lock);
 
+       INIT_WORK(&chip->red_work, lp5521_red_work);
+       INIT_WORK(&chip->green_work, lp5521_green_work);
+       INIT_WORK(&chip->blue_work, lp5521_blue_work);
+
        ret = lp5521_configure(client);
        if (ret < 0) {
                dev_err(&client->dev, "lp5521 error configuring chip \n");
@@ -516,19 +616,61 @@ static int __init lp5521_probe(struct i2c_client *client,
        }
 
        /* Set default values */
-       chip->mode      = LP5521_MODE_DIRECT_CONTROL;
-       chip->red       = 1;
-       chip->green     = 1;
-       chip->blue      = 1;
+       chip->mode      = pdata->mode;
+       chip->red       = pdata->red_present;
+       chip->green     = pdata->green_present;
+       chip->blue      = pdata->blue_present;
+
+       chip->ledr.brightness_set = lp5521_red_set;
+       chip->ledr.default_trigger = NULL;
+       snprintf(name, sizeof(name), "%s::red", pdata->label);
+       chip->ledr.name = name;
+       ret = led_classdev_register(&client->dev, &chip->ledr);
+       if (ret < 0) {
+               dev_dbg(&client->dev, "failed to register led %s, %d\n",
+                               chip->ledb.name, ret);
+               goto fail1;
+       }
+
+       chip->ledg.brightness_set = lp5521_green_set;
+       chip->ledg.default_trigger = NULL;
+       snprintf(name, sizeof(name), "%s::green", pdata->label);
+       chip->ledg.name = name;
+       ret = led_classdev_register(&client->dev, &chip->ledg);
+       if (ret < 0) {
+               dev_dbg(&client->dev, "failed to register led %s, %d\n",
+                               chip->ledb.name, ret);
+               goto fail2;
+       }
+
+       chip->ledb.brightness_set = lp5521_blue_set;
+       chip->ledb.default_trigger = NULL;
+       snprintf(name, sizeof(name), "%s::blue", pdata->label);
+       chip->ledb.name = name;
+       ret = led_classdev_register(&client->dev, &chip->ledb);
+       if (ret < 0) {
+               dev_dbg(&client->dev, "failed to register led %s, %d\n", chip->ledb.name, ret);
+               goto fail3;
+       }
 
        ret = lp5521_register_sysfs(client);
-       if (ret)
+       if (ret) {
                dev_err(&client->dev, "lp5521 registering sysfs failed \n");
+               goto fail4;
+       }
 
-       return ret;
+       return 0;
 
+fail4:
+       led_classdev_unregister(&chip->ledb);
+fail3:
+       led_classdev_unregister(&chip->ledg);
+fail2:
+       led_classdev_unregister(&chip->ledr);
 fail1:
+       i2c_set_clientdata(client, NULL);
        kfree(chip);
+
        return ret;
 }
 
@@ -537,6 +679,12 @@ static int __exit lp5521_remove(struct i2c_client *client)
        struct lp5521_chip *chip = i2c_get_clientdata(client);
 
        lp5521_unregister_sysfs(client);
+       i2c_set_clientdata(client, NULL);
+
+       led_classdev_unregister(&chip->ledb);
+       led_classdev_unregister(&chip->ledg);
+       led_classdev_unregister(&chip->ledr);
+
        kfree(chip);
 
        return 0;
diff --git a/include/linux/i2c/lp5521.h b/include/linux/i2c/lp5521.h
new file mode 100644 (file)
index 0000000..070e8be
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * lp5521.h - header for LP5521 LED driver
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __LP5521_H_
+#define __LP5521_H_
+
+enum lp5521_mode {
+       LP5521_MODE_LOAD,
+       LP5521_MODE_RUN,
+       LP5521_MODE_DIRECT_CONTROL,
+};
+
+struct lp5521_platform_data {
+       enum lp5521_mode        mode;
+
+       unsigned                red_present:1;
+       unsigned                green_present:1;
+       unsigned                blue_present:1;
+
+       const char              *label;
+};
+
+#endif /* End of __LP5521_H */