aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds/leds-lp5523.c
diff options
context:
space:
mode:
authorSamu Onkalo <samu.p.onkalo@nokia.com>2011-01-12 19:59:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 11:03:05 -0500
commitfbac0812de0455c6af3e1f29fccffc207073b7eb (patch)
tree7a098b7b4e8d945c74252022a757b90d2b552f3a /drivers/leds/leds-lp5523.c
parent278ad4fd0e7517f1d74b8fc1c8347cad34a09b02 (diff)
leds: lp5523: fix circular locking
Driver contained possibility for circular locking. One lock is held by sysfs-core and another one by the driver itself. This happened when the driver created or removed sysfs entries dynamically. There is no real need to do those operations. Now all the sysfs entries are created at probe and removed at removal. Engine load and mux configuration sysfs entries are now visible all the time. However, access to the entries fails if the engine is disabled or running. Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com> Cc: Arun Murthy <arun.murthy@stericsson.com> Reviewed-by: Ilkka Koskinen <ilkka.koskinen@nokia.com> Cc: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/leds/leds-lp5523.c')
-rw-r--r--drivers/leds/leds-lp5523.c56
1 files changed, 16 insertions, 40 deletions
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 6cb41607519d..d0c4068ecddd 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -105,7 +105,6 @@
105#define SHIFT_MASK(id) (((id) - 1) * 2) 105#define SHIFT_MASK(id) (((id) - 1) * 2)
106 106
107struct lp5523_engine { 107struct lp5523_engine {
108 const struct attribute_group *attributes;
109 int id; 108 int id;
110 u8 mode; 109 u8 mode;
111 u8 prog_page; 110 u8 prog_page;
@@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev,
403 struct i2c_client *client = to_i2c_client(dev); 402 struct i2c_client *client = to_i2c_client(dev);
404 struct lp5523_chip *chip = i2c_get_clientdata(client); 403 struct lp5523_chip *chip = i2c_get_clientdata(client);
405 u16 mux = 0; 404 u16 mux = 0;
405 ssize_t ret;
406 406
407 if (lp5523_mux_parse(buf, &mux, len)) 407 if (lp5523_mux_parse(buf, &mux, len))
408 return -EINVAL; 408 return -EINVAL;
409 409
410 mutex_lock(&chip->lock);
411 ret = -EINVAL;
412 if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD)
413 goto leave;
414
410 if (lp5523_load_mux(&chip->engines[nr - 1], mux)) 415 if (lp5523_load_mux(&chip->engines[nr - 1], mux))
411 return -EINVAL; 416 goto leave;
412 417
413 return len; 418 ret = len;
419leave:
420 mutex_unlock(&chip->lock);
421 return ret;
414} 422}
415 423
416#define store_leds(nr) \ 424#define store_leds(nr) \
@@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
556 564
557 mutex_lock(&chip->lock); 565 mutex_lock(&chip->lock);
558 566
559 ret = lp5523_load_program(engine, pattern); 567 if (engine->mode == LP5523_CMD_LOAD)
568 ret = lp5523_load_program(engine, pattern);
569 else
570 ret = -EINVAL;
571
560 mutex_unlock(&chip->lock); 572 mutex_unlock(&chip->lock);
561 573
562 if (ret) { 574 if (ret) {
@@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = {
737 &dev_attr_engine2_mode.attr, 749 &dev_attr_engine2_mode.attr,
738 &dev_attr_engine3_mode.attr, 750 &dev_attr_engine3_mode.attr,
739 &dev_attr_selftest.attr, 751 &dev_attr_selftest.attr,
740 NULL
741};
742
743static struct attribute *lp5523_engine1_attributes[] = {
744 &dev_attr_engine1_load.attr, 752 &dev_attr_engine1_load.attr,
745 &dev_attr_engine1_leds.attr, 753 &dev_attr_engine1_leds.attr,
746 NULL
747};
748
749static struct attribute *lp5523_engine2_attributes[] = {
750 &dev_attr_engine2_load.attr, 754 &dev_attr_engine2_load.attr,
751 &dev_attr_engine2_leds.attr, 755 &dev_attr_engine2_leds.attr,
752 NULL
753};
754
755static struct attribute *lp5523_engine3_attributes[] = {
756 &dev_attr_engine3_load.attr, 756 &dev_attr_engine3_load.attr,
757 &dev_attr_engine3_leds.attr, 757 &dev_attr_engine3_leds.attr,
758 NULL
759}; 758};
760 759
761static const struct attribute_group lp5523_group = { 760static const struct attribute_group lp5523_group = {
762 .attrs = lp5523_attributes, 761 .attrs = lp5523_attributes,
763}; 762};
764 763
765static const struct attribute_group lp5523_engine_group[] = {
766 {.attrs = lp5523_engine1_attributes },
767 {.attrs = lp5523_engine2_attributes },
768 {.attrs = lp5523_engine3_attributes },
769};
770
771static int lp5523_register_sysfs(struct i2c_client *client) 764static int lp5523_register_sysfs(struct i2c_client *client)
772{ 765{
773 struct device *dev = &client->dev; 766 struct device *dev = &client->dev;
@@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
788 781
789 sysfs_remove_group(&dev->kobj, &lp5523_group); 782 sysfs_remove_group(&dev->kobj, &lp5523_group);
790 783
791 for (i = 0; i < ARRAY_SIZE(chip->engines); i++)
792 if (chip->engines[i].mode == LP5523_CMD_LOAD)
793 sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]);
794
795 for (i = 0; i < chip->num_leds; i++) 784 for (i = 0; i < chip->num_leds; i++)
796 sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, 785 sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
797 &lp5523_led_attribute_group); 786 &lp5523_led_attribute_group);
@@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
802/*--------------------------------------------------------------*/ 791/*--------------------------------------------------------------*/
803static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) 792static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
804{ 793{
805 /* engine to chip */
806 struct lp5523_chip *chip = engine_to_lp5523(engine);
807 struct i2c_client *client = chip->client;
808 struct device *dev = &client->dev;
809 int ret = 0; 794 int ret = 0;
810 795
811 /* if in that mode already do nothing, except for run */ 796 /* 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)
817 } else if (mode == LP5523_CMD_LOAD) { 802 } else if (mode == LP5523_CMD_LOAD) {
818 lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); 803 lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
819 lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); 804 lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
820
821 ret = sysfs_create_group(&dev->kobj, engine->attributes);
822 if (ret)
823 return ret;
824 } else if (mode == LP5523_CMD_DISABLED) { 805 } else if (mode == LP5523_CMD_DISABLED) {
825 lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); 806 lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
826 } 807 }
827 808
828 /* remove load attribute from sysfs if not in load mode */
829 if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD)
830 sysfs_remove_group(&dev->kobj, engine->attributes);
831
832 engine->mode = mode; 809 engine->mode = mode;
833 810
834 return ret; 811 return ret;
@@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
845 engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); 822 engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
846 engine->prog_page = id - 1; 823 engine->prog_page = id - 1;
847 engine->mux_page = id + 2; 824 engine->mux_page = id + 2;
848 engine->attributes = &lp5523_engine_group[id - 1];
849 825
850 return 0; 826 return 0;
851} 827}