diff options
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/leds-lp5521.c | 57 | ||||
-rw-r--r-- | drivers/leds/leds-lp5523.c | 59 | ||||
-rw-r--r-- | drivers/leds/leds-pca9532.c | 66 | ||||
-rw-r--r-- | drivers/leds/ledtrig-backlight.c | 61 |
4 files changed, 115 insertions, 128 deletions
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 33facd0c45d..80a3ae3c00b 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -98,7 +98,6 @@ #define LP5521_EXT_CLK_USED 0x08 struct lp5521_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -225,25 +224,22 @@ static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) curr); } -static void lp5521_init_engine(struct lp5521_chip *chip, - const struct attribute_group *attr_group) +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; - chip->engines[i].attributes = &attr_group[i]; } } -static int lp5521_configure(struct i2c_client *client, - const struct attribute_group *attr_group) +static int lp5521_configure(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); int ret; - lp5521_init_engine(chip, attr_group); + lp5521_init_engine(chip); /* Set all PWMs to direct control mode */ ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); @@ -329,9 +325,6 @@ static int lp5521_detect(struct i2c_client *client) /* Set engine mode and create appropriate sysfs attributes, if required. */ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) { - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -343,18 +336,10 @@ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) } else if (mode == LP5521_CMD_LOAD) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5521_CMD_DISABLED) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -373,6 +358,8 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, while ((offset < len - 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(c, "%2x", &cmd); if (ret != 1) goto fail; @@ -387,7 +374,10 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, goto fail; mutex_lock(&chip->lock); - ret = lp5521_load_program(engine, pattern); + if (engine->mode == LP5521_CMD_LOAD) + ret = lp5521_load_program(engine, pattern); + else + ret = -EINVAL; mutex_unlock(&chip->lock); if (ret) { @@ -574,20 +564,8 @@ static struct attribute *lp5521_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5521_engine1_attributes[] = { &dev_attr_engine1_load.attr, - NULL -}; - -static struct attribute *lp5521_engine2_attributes[] = { &dev_attr_engine2_load.attr, - NULL -}; - -static struct attribute *lp5521_engine3_attributes[] = { &dev_attr_engine3_load.attr, NULL }; @@ -596,12 +574,6 @@ static const struct attribute_group lp5521_group = { .attrs = lp5521_attributes, }; -static const struct attribute_group lp5521_engine_group[] = { - {.attrs = lp5521_engine1_attributes }, - {.attrs = lp5521_engine2_attributes }, - {.attrs = lp5521_engine3_attributes }, -}; - static int lp5521_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -616,12 +588,6 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5521_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - if (chip->engines[i].mode == LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, - chip->engines[i].attributes); - } - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5521_led_attribute_group); @@ -651,7 +617,8 @@ static int __init lp5521_init_led(struct lp5521_led *led, return -EINVAL; } - snprintf(name, sizeof(name), "%s:channel%d", client->name, chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: client->name, chan); led->cdev.brightness_set = lp5521_set_brightness; led->cdev.name = name; res = led_classdev_register(dev, &led->cdev); @@ -723,7 +690,7 @@ static int lp5521_probe(struct i2c_client *client, dev_info(&client->dev, "%s programmable led chip found\n", id->name); - ret = lp5521_configure(client, lp5521_engine_group); + ret = lp5521_configure(client); if (ret < 0) { dev_err(&client->dev, "error configuring chip\n"); goto fail2; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 0cc4ead2fd8..d0c4068ecdd 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -105,7 +105,6 @@ #define SHIFT_MASK(id) (((id) - 1) * 2) struct lp5523_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lp5523_chip *chip = i2c_get_clientdata(client); u16 mux = 0; + ssize_t ret; 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 (lp5523_load_mux(&chip->engines[nr - 1], mux)) - return -EINVAL; + goto leave; - return len; + ret = len; +leave: + mutex_unlock(&chip->lock); + return ret; } #define store_leds(nr) \ @@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine, mutex_lock(&chip->lock); - ret = lp5523_load_program(engine, pattern); + if (engine->mode == LP5523_CMD_LOAD) + ret = lp5523_load_program(engine, pattern); + else + ret = -EINVAL; + mutex_unlock(&chip->lock); if (ret) { @@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5523_engine1_attributes[] = { &dev_attr_engine1_load.attr, &dev_attr_engine1_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine2_attributes[] = { &dev_attr_engine2_load.attr, &dev_attr_engine2_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine3_attributes[] = { &dev_attr_engine3_load.attr, &dev_attr_engine3_leds.attr, - NULL }; static const struct attribute_group lp5523_group = { .attrs = lp5523_attributes, }; -static const struct attribute_group lp5523_engine_group[] = { - {.attrs = lp5523_engine1_attributes }, - {.attrs = lp5523_engine2_attributes }, - {.attrs = lp5523_engine3_attributes }, -}; - static int lp5523_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5523_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) - if (chip->engines[i].mode == LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]); - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5523_led_attribute_group); @@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) /*--------------------------------------------------------------*/ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) { - /* engine to chip */ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -817,18 +802,10 @@ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) } else if (mode == LP5523_CMD_LOAD) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5523_CMD_DISABLED) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); engine->prog_page = id - 1; engine->mux_page = id + 2; - engine->attributes = &lp5523_engine_group[id - 1]; return 0; } @@ -870,7 +846,8 @@ static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, return -EINVAL; } - snprintf(name, 32, "lp5523:channel%d", chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: "lp5523", chan); led->cdev.name = name; led->cdev.brightness_set = lp5523_set_brightness; diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 43d08756d82..afac338d502 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -200,6 +200,32 @@ static void pca9532_led_work(struct work_struct *work) pca9532_setled(led); } +static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs) +{ + int i = n_devs; + + if (!data) + return; + + while (--i >= 0) { + switch (data->leds[i].type) { + case PCA9532_TYPE_NONE: + break; + case PCA9532_TYPE_LED: + led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); + break; + case PCA9532_TYPE_N2100_BEEP: + if (data->idev != NULL) { + input_unregister_device(data->idev); + cancel_work_sync(&data->work); + data->idev = NULL; + } + break; + } + } +} + static int pca9532_configure(struct i2c_client *client, struct pca9532_data *data, struct pca9532_platform_data *pdata) { @@ -274,25 +300,7 @@ static int pca9532_configure(struct i2c_client *client, return 0; exit: - if (i > 0) - for (i = i - 1; i >= 0; i--) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, i); return err; } @@ -329,25 +337,7 @@ static int pca9532_probe(struct i2c_client *client, static int pca9532_remove(struct i2c_client *client) { struct pca9532_data *data = i2c_get_clientdata(client); - int i; - for (i = 0; i < 16; i++) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, 16); kfree(data); return 0; } diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c index f948e57bd9b..2b513a2ad7d 100644 --- a/drivers/leds/ledtrig-backlight.c +++ b/drivers/leds/ledtrig-backlight.c @@ -26,6 +26,7 @@ struct bl_trig_notifier { int brightness; int old_status; struct notifier_block notifier; + unsigned invert; }; static int fb_notifier_callback(struct notifier_block *p, @@ -36,23 +37,64 @@ static int fb_notifier_callback(struct notifier_block *p, struct led_classdev *led = n->led; struct fb_event *fb_event = data; int *blank = fb_event->data; + int new_status = *blank ? BLANK : UNBLANK; switch (event) { case FB_EVENT_BLANK : - if (*blank && n->old_status == UNBLANK) { + if (new_status == n->old_status) + break; + + if ((n->old_status == UNBLANK) ^ n->invert) { n->brightness = led->brightness; led_set_brightness(led, LED_OFF); - n->old_status = BLANK; - } else if (!*blank && n->old_status == BLANK) { + } else { led_set_brightness(led, n->brightness); - n->old_status = UNBLANK; } + + n->old_status = new_status; + break; } return 0; } +static ssize_t bl_trig_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + + return sprintf(buf, "%u\n", n->invert); +} + +static ssize_t bl_trig_invert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t num) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + unsigned long invert; + int ret; + + ret = strict_strtoul(buf, 10, &invert); + if (ret < 0) + return ret; + + if (invert > 1) + return -EINVAL; + + n->invert = invert; + + /* After inverting, we need to update the LED. */ + if ((n->old_status == BLANK) ^ n->invert) + led_set_brightness(led, LED_OFF); + else + led_set_brightness(led, n->brightness); + + return num; +} +static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store); + static void bl_trig_activate(struct led_classdev *led) { int ret; @@ -66,6 +108,10 @@ static void bl_trig_activate(struct led_classdev *led) return; } + ret = device_create_file(led->dev, &dev_attr_inverted); + if (ret) + goto err_invert; + n->led = led; n->brightness = led->brightness; n->old_status = UNBLANK; @@ -74,6 +120,12 @@ static void bl_trig_activate(struct led_classdev *led) ret = fb_register_client(&n->notifier); if (ret) dev_err(led->dev, "unable to register backlight trigger\n"); + + return; + +err_invert: + led->trigger_data = NULL; + kfree(n); } static void bl_trig_deactivate(struct led_classdev *led) @@ -82,6 +134,7 @@ static void bl_trig_deactivate(struct led_classdev *led) (struct bl_trig_notifier *) led->trigger_data; if (n) { + device_remove_file(led->dev, &dev_attr_inverted); fb_unregister_client(&n->notifier); kfree(n); } |