include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / leds / leds-bd2802.c
index 6832b9f..286b501 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/leds.h>
 #include <linux/leds-bd2802.h>
+#include <linux/slab.h>
 
 
 #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
@@ -97,6 +98,10 @@ struct bd2802_led {
        enum led_ids                    led_id;
        enum led_colors                 color;
        enum led_bits                   state;
+
+       /* General attributes of RGB LEDs */
+       int                             wave_pattern;
+       int                             rgb_current;
 };
 
 
@@ -254,7 +259,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
                bd2802_reset_cancel(led);
 
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
@@ -275,9 +280,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
-       bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
+       bd2802_write_byte(led->client, reg, led->wave_pattern);
 
        bd2802_enable(led, id);
        bd2802_update_state(led, id, color, BD2802_BLINK);
@@ -406,7 +411,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
                ret = device_create_file(&led->client->dev,
                                                bd2802_addr_attributes[i]);
                if (ret) {
-                       dev_err(&led->client->dev, "failed to sysfs file %s\n",
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
                                        bd2802_addr_attributes[i]->attr.name);
                        goto failed_remove_files;
                }
@@ -483,6 +488,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
        .store = bd2802_store_adv_conf,
 };
 
+#define BD2802_CONTROL_ATTR(attr_name, name_str)                       \
+static ssize_t bd2802_show_##attr_name(struct device *dev,             \
+       struct device_attribute *attr, char *buf)                       \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       ssize_t ret;                                                    \
+       down_read(&led->rwsem);                                         \
+       ret = sprintf(buf, "0x%02x\n", led->attr_name);                 \
+       up_read(&led->rwsem);                                           \
+       return ret;                                                     \
+}                                                                      \
+static ssize_t bd2802_store_##attr_name(struct device *dev,            \
+       struct device_attribute *attr, const char *buf, size_t count)   \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       unsigned long val;                                              \
+       int ret;                                                        \
+       if (!count)                                                     \
+               return -EINVAL;                                         \
+       ret = strict_strtoul(buf, 16, &val);                            \
+       if (ret)                                                        \
+               return ret;                                             \
+       down_write(&led->rwsem);                                        \
+       led->attr_name = val;                                           \
+       up_write(&led->rwsem);                                          \
+       return count;                                                   \
+}                                                                      \
+static struct device_attribute bd2802_##attr_name##_attr = {           \
+       .attr = {                                                       \
+               .name = name_str,                                       \
+               .mode = 0644,                                           \
+               .owner = THIS_MODULE                                    \
+       },                                                              \
+       .show = bd2802_show_##attr_name,                                \
+       .store = bd2802_store_##attr_name,                              \
+};
+
+BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
+BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
+
+static struct device_attribute *bd2802_attributes[] = {
+       &bd2802_adv_conf_attr,
+       &bd2802_wave_pattern_attr,
+       &bd2802_rgb_current_attr,
+};
+
 static void bd2802_led_work(struct work_struct *work)
 {
        struct bd2802_led *led = container_of(work, struct bd2802_led, work);
@@ -635,7 +686,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
 {
        struct bd2802_led *led;
        struct bd2802_led_platform_data *pdata;
-       int ret;
+       int ret, i;
 
        led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
        if (!led) {
@@ -665,13 +716,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        /* To save the power, reset BD2802 after detecting */
        gpio_set_value(led->pdata->reset_gpio, 0);
 
+       /* Default attributes */
+       led->wave_pattern = BD2802_PATTERN_HALF;
+       led->rgb_current = BD2802_CURRENT_032;
+
        init_rwsem(&led->rwsem);
 
-       ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
-       if (ret) {
-               dev_err(&client->dev, "failed to create sysfs file %s\n",
-                                       bd2802_adv_conf_attr.attr.name);
-               goto failed_free;
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
+               ret = device_create_file(&led->client->dev,
+                                               bd2802_attributes[i]);
+               if (ret) {
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
+                                       bd2802_attributes[i]->attr.name);
+                       goto failed_unregister_dev_file;
+               }
        }
 
        ret = bd2802_register_led_classdev(led);
@@ -681,7 +739,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        return 0;
 
 failed_unregister_dev_file:
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i--; i >= 0; i--)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
 failed_free:
        i2c_set_clientdata(client, NULL);
        kfree(led);
@@ -692,12 +751,14 @@ failed_free:
 static int __exit bd2802_remove(struct i2c_client *client)
 {
        struct bd2802_led *led = i2c_get_clientdata(client);
+       int i;
 
-       bd2802_unregister_led_classdev(led);
        gpio_set_value(led->pdata->reset_gpio, 0);
+       bd2802_unregister_led_classdev(led);
        if (led->adf_on)
                bd2802_disable_adv_conf(led);
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
        i2c_set_clientdata(client, NULL);
        kfree(led);
 
@@ -756,4 +817,4 @@ module_exit(bd2802_exit);
 
 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 MODULE_DESCRIPTION("BD2802 LED driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");