X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fi2c%2Fchips%2Flp5521.c;h=b3ba52ab6c452082a9464b7bfc5af6d9111af6fc;hb=0451712f9a0f310eb4b486a871c4d9b213368908;hp=9e94ff8b52924e92d744236080f2bed013f46271;hpb=3bcc9fdb78c072876dc10281b028d465b4434266;p=linux-2.6-omap-h63xx.git diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c index 9e94ff8b529..b3ba52ab6c4 100644 --- a/drivers/i2c/chips/lp5521.c +++ b/drivers/i2c/chips/lp5521.c @@ -4,6 +4,7 @@ * Copyright (C) 2007 Nokia Corporation * * Written by Mathias Nyman + * Updated by Felipe Balbi * * 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 @@ -23,7 +24,10 @@ #include #include #include +#include #include +#include +#include #define LP5521_DRIVER_NAME "lp5521" @@ -65,17 +69,21 @@ #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;