Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * leds-bd2802.c - RGB LED Driver
0004  *
0005  * Copyright (C) 2009 Samsung Electronics
0006  * Kim Kyuwon <q1.kim@samsung.com>
0007  *
0008  * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/i2c.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/delay.h>
0015 #include <linux/leds.h>
0016 #include <linux/leds-bd2802.h>
0017 #include <linux/slab.h>
0018 #include <linux/pm.h>
0019 
0020 #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
0021 
0022 #define BD2802_LED_OFFSET       0xa
0023 #define BD2802_COLOR_OFFSET     0x3
0024 
0025 #define BD2802_REG_CLKSETUP     0x00
0026 #define BD2802_REG_CONTROL      0x01
0027 #define BD2802_REG_HOURSETUP        0x02
0028 #define BD2802_REG_CURRENT1SETUP    0x03
0029 #define BD2802_REG_CURRENT2SETUP    0x04
0030 #define BD2802_REG_WAVEPATTERN      0x05
0031 
0032 #define BD2802_CURRENT_032      0x10 /* 3.2mA */
0033 #define BD2802_CURRENT_000      0x00 /* 0.0mA */
0034 
0035 #define BD2802_PATTERN_FULL     0x07
0036 #define BD2802_PATTERN_HALF     0x03
0037 
0038 enum led_ids {
0039     LED1,
0040     LED2,
0041     LED_NUM,
0042 };
0043 
0044 enum led_colors {
0045     RED,
0046     GREEN,
0047     BLUE,
0048 };
0049 
0050 enum led_bits {
0051     BD2802_OFF,
0052     BD2802_BLINK,
0053     BD2802_ON,
0054 };
0055 
0056 /*
0057  * State '0' : 'off'
0058  * State '1' : 'blink'
0059  * State '2' : 'on'.
0060  */
0061 struct led_state {
0062     unsigned r:2;
0063     unsigned g:2;
0064     unsigned b:2;
0065 };
0066 
0067 struct bd2802_led {
0068     struct bd2802_led_platform_data *pdata;
0069     struct i2c_client       *client;
0070     struct gpio_desc        *reset;
0071     struct rw_semaphore     rwsem;
0072 
0073     struct led_state        led[2];
0074 
0075     /*
0076      * Making led_classdev as array is not recommended, because array
0077      * members prevent using 'container_of' macro. So repetitive works
0078      * are needed.
0079      */
0080     struct led_classdev     cdev_led1r;
0081     struct led_classdev     cdev_led1g;
0082     struct led_classdev     cdev_led1b;
0083     struct led_classdev     cdev_led2r;
0084     struct led_classdev     cdev_led2g;
0085     struct led_classdev     cdev_led2b;
0086 
0087     /*
0088      * Advanced Configuration Function(ADF) mode:
0089      * In ADF mode, user can set registers of BD2802GU directly,
0090      * therefore BD2802GU doesn't enter reset state.
0091      */
0092     int             adf_on;
0093 
0094     enum led_ids            led_id;
0095     enum led_colors         color;
0096     enum led_bits           state;
0097 
0098     /* General attributes of RGB LEDs */
0099     int             wave_pattern;
0100     int             rgb_current;
0101 };
0102 
0103 
0104 /*--------------------------------------------------------------*/
0105 /*  BD2802GU helper functions                   */
0106 /*--------------------------------------------------------------*/
0107 
0108 static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
0109                             enum led_colors color)
0110 {
0111     switch (color) {
0112     case RED:
0113         return !led->led[id].r;
0114     case GREEN:
0115         return !led->led[id].g;
0116     case BLUE:
0117         return !led->led[id].b;
0118     default:
0119         dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
0120         return -EINVAL;
0121     }
0122 }
0123 
0124 static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
0125 {
0126     if (led->led[id].r || led->led[id].g || led->led[id].b)
0127         return 0;
0128 
0129     return 1;
0130 }
0131 
0132 static inline int bd2802_is_all_off(struct bd2802_led *led)
0133 {
0134     int i;
0135 
0136     for (i = 0; i < LED_NUM; i++)
0137         if (!bd2802_is_led_off(led, i))
0138             return 0;
0139 
0140     return 1;
0141 }
0142 
0143 static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
0144 {
0145     return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
0146 }
0147 
0148 static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
0149                                 u8 reg_offset)
0150 {
0151     return reg_offset + bd2802_get_base_offset(id, color);
0152 }
0153 
0154 
0155 /*--------------------------------------------------------------*/
0156 /*  BD2802GU core functions                 */
0157 /*--------------------------------------------------------------*/
0158 
0159 static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
0160 {
0161     int ret = i2c_smbus_write_byte_data(client, reg, val);
0162     if (ret >= 0)
0163         return 0;
0164 
0165     dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
0166                         __func__, reg, val, ret);
0167 
0168     return ret;
0169 }
0170 
0171 static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
0172                 enum led_colors color, enum led_bits led_bit)
0173 {
0174     int i;
0175     u8 value;
0176 
0177     for (i = 0; i < LED_NUM; i++) {
0178         if (i == id) {
0179             switch (color) {
0180             case RED:
0181                 led->led[i].r = led_bit;
0182                 break;
0183             case GREEN:
0184                 led->led[i].g = led_bit;
0185                 break;
0186             case BLUE:
0187                 led->led[i].b = led_bit;
0188                 break;
0189             default:
0190                 dev_err(&led->client->dev,
0191                     "%s: Invalid color\n", __func__);
0192                 return;
0193             }
0194         }
0195     }
0196 
0197     if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
0198         return;
0199 
0200     if (!bd2802_is_led_off(led, id))
0201         return;
0202 
0203     if (bd2802_is_all_off(led) && !led->adf_on) {
0204         gpiod_set_value(led->reset, 1);
0205         return;
0206     }
0207 
0208     /*
0209      * In this case, other led is turned on, and current led is turned
0210      * off. So set RGB LED Control register to stop the current RGB LED
0211      */
0212     value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
0213     bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
0214 }
0215 
0216 static void bd2802_configure(struct bd2802_led *led)
0217 {
0218     struct bd2802_led_platform_data *pdata = led->pdata;
0219     u8 reg;
0220 
0221     reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
0222     bd2802_write_byte(led->client, reg, pdata->rgb_time);
0223 
0224     reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
0225     bd2802_write_byte(led->client, reg, pdata->rgb_time);
0226 }
0227 
0228 static void bd2802_reset_cancel(struct bd2802_led *led)
0229 {
0230     gpiod_set_value(led->reset, 0);
0231     udelay(100);
0232     bd2802_configure(led);
0233 }
0234 
0235 static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
0236 {
0237     enum led_ids other_led = (id == LED1) ? LED2 : LED1;
0238     u8 value, other_led_on;
0239 
0240     other_led_on = !bd2802_is_led_off(led, other_led);
0241     if (id == LED1)
0242         value = LED_CTL(other_led_on, 1);
0243     else
0244         value = LED_CTL(1 , other_led_on);
0245 
0246     bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
0247 }
0248 
0249 static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
0250                             enum led_colors color)
0251 {
0252     u8 reg;
0253 
0254     if (bd2802_is_all_off(led) && !led->adf_on)
0255         bd2802_reset_cancel(led);
0256 
0257     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
0258     bd2802_write_byte(led->client, reg, led->rgb_current);
0259     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
0260     bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
0261     reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
0262     bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
0263 
0264     bd2802_enable(led, id);
0265     bd2802_update_state(led, id, color, BD2802_ON);
0266 }
0267 
0268 static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
0269                             enum led_colors color)
0270 {
0271     u8 reg;
0272 
0273     if (bd2802_is_all_off(led) && !led->adf_on)
0274         bd2802_reset_cancel(led);
0275 
0276     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
0277     bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
0278     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
0279     bd2802_write_byte(led->client, reg, led->rgb_current);
0280     reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
0281     bd2802_write_byte(led->client, reg, led->wave_pattern);
0282 
0283     bd2802_enable(led, id);
0284     bd2802_update_state(led, id, color, BD2802_BLINK);
0285 }
0286 
0287 static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
0288                 enum led_colors color, enum led_bits led_bit)
0289 {
0290     if (led_bit == BD2802_OFF) {
0291         dev_err(&led->client->dev,
0292                     "Only 'blink' and 'on' are allowed\n");
0293         return;
0294     }
0295 
0296     if (led_bit == BD2802_BLINK)
0297         bd2802_set_blink(led, id, color);
0298     else
0299         bd2802_set_on(led, id, color);
0300 }
0301 
0302 static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
0303                             enum led_colors color)
0304 {
0305     u8 reg;
0306 
0307     if (bd2802_is_rgb_off(led, id, color))
0308         return;
0309 
0310     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
0311     bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
0312     reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
0313     bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
0314 
0315     bd2802_update_state(led, id, color, BD2802_OFF);
0316 }
0317 
0318 #define BD2802_SET_REGISTER(reg_addr, reg_name)             \
0319 static ssize_t bd2802_store_reg##reg_addr(struct device *dev,       \
0320     struct device_attribute *attr, const char *buf, size_t count)   \
0321 {                                   \
0322     struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
0323     unsigned long val;                      \
0324     int ret;                            \
0325     if (!count)                         \
0326         return -EINVAL;                     \
0327     ret = kstrtoul(buf, 16, &val);                  \
0328     if (ret)                            \
0329         return ret;                     \
0330     down_write(&led->rwsem);                    \
0331     bd2802_write_byte(led->client, reg_addr, (u8) val);     \
0332     up_write(&led->rwsem);                      \
0333     return count;                           \
0334 }                                   \
0335 static struct device_attribute bd2802_reg##reg_addr##_attr = {      \
0336     .attr = {.name = reg_name, .mode = 0644},           \
0337     .store = bd2802_store_reg##reg_addr,                \
0338 };
0339 
0340 BD2802_SET_REGISTER(0x00, "0x00");
0341 BD2802_SET_REGISTER(0x01, "0x01");
0342 BD2802_SET_REGISTER(0x02, "0x02");
0343 BD2802_SET_REGISTER(0x03, "0x03");
0344 BD2802_SET_REGISTER(0x04, "0x04");
0345 BD2802_SET_REGISTER(0x05, "0x05");
0346 BD2802_SET_REGISTER(0x06, "0x06");
0347 BD2802_SET_REGISTER(0x07, "0x07");
0348 BD2802_SET_REGISTER(0x08, "0x08");
0349 BD2802_SET_REGISTER(0x09, "0x09");
0350 BD2802_SET_REGISTER(0x0a, "0x0a");
0351 BD2802_SET_REGISTER(0x0b, "0x0b");
0352 BD2802_SET_REGISTER(0x0c, "0x0c");
0353 BD2802_SET_REGISTER(0x0d, "0x0d");
0354 BD2802_SET_REGISTER(0x0e, "0x0e");
0355 BD2802_SET_REGISTER(0x0f, "0x0f");
0356 BD2802_SET_REGISTER(0x10, "0x10");
0357 BD2802_SET_REGISTER(0x11, "0x11");
0358 BD2802_SET_REGISTER(0x12, "0x12");
0359 BD2802_SET_REGISTER(0x13, "0x13");
0360 BD2802_SET_REGISTER(0x14, "0x14");
0361 BD2802_SET_REGISTER(0x15, "0x15");
0362 
0363 static struct device_attribute *bd2802_addr_attributes[] = {
0364     &bd2802_reg0x00_attr,
0365     &bd2802_reg0x01_attr,
0366     &bd2802_reg0x02_attr,
0367     &bd2802_reg0x03_attr,
0368     &bd2802_reg0x04_attr,
0369     &bd2802_reg0x05_attr,
0370     &bd2802_reg0x06_attr,
0371     &bd2802_reg0x07_attr,
0372     &bd2802_reg0x08_attr,
0373     &bd2802_reg0x09_attr,
0374     &bd2802_reg0x0a_attr,
0375     &bd2802_reg0x0b_attr,
0376     &bd2802_reg0x0c_attr,
0377     &bd2802_reg0x0d_attr,
0378     &bd2802_reg0x0e_attr,
0379     &bd2802_reg0x0f_attr,
0380     &bd2802_reg0x10_attr,
0381     &bd2802_reg0x11_attr,
0382     &bd2802_reg0x12_attr,
0383     &bd2802_reg0x13_attr,
0384     &bd2802_reg0x14_attr,
0385     &bd2802_reg0x15_attr,
0386 };
0387 
0388 static void bd2802_enable_adv_conf(struct bd2802_led *led)
0389 {
0390     int i, ret;
0391 
0392     for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
0393         ret = device_create_file(&led->client->dev,
0394                         bd2802_addr_attributes[i]);
0395         if (ret) {
0396             dev_err(&led->client->dev, "failed: sysfs file %s\n",
0397                     bd2802_addr_attributes[i]->attr.name);
0398             goto failed_remove_files;
0399         }
0400     }
0401 
0402     if (bd2802_is_all_off(led))
0403         bd2802_reset_cancel(led);
0404 
0405     led->adf_on = 1;
0406 
0407     return;
0408 
0409 failed_remove_files:
0410     for (i--; i >= 0; i--)
0411         device_remove_file(&led->client->dev,
0412                         bd2802_addr_attributes[i]);
0413 }
0414 
0415 static void bd2802_disable_adv_conf(struct bd2802_led *led)
0416 {
0417     int i;
0418 
0419     for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
0420         device_remove_file(&led->client->dev,
0421                         bd2802_addr_attributes[i]);
0422 
0423     if (bd2802_is_all_off(led))
0424         gpiod_set_value(led->reset, 1);
0425 
0426     led->adf_on = 0;
0427 }
0428 
0429 static ssize_t bd2802_show_adv_conf(struct device *dev,
0430     struct device_attribute *attr, char *buf)
0431 {
0432     struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
0433     ssize_t ret;
0434 
0435     down_read(&led->rwsem);
0436     if (led->adf_on)
0437         ret = sprintf(buf, "on\n");
0438     else
0439         ret = sprintf(buf, "off\n");
0440     up_read(&led->rwsem);
0441 
0442     return ret;
0443 }
0444 
0445 static ssize_t bd2802_store_adv_conf(struct device *dev,
0446     struct device_attribute *attr, const char *buf, size_t count)
0447 {
0448     struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
0449 
0450     if (!count)
0451         return -EINVAL;
0452 
0453     down_write(&led->rwsem);
0454     if (!led->adf_on && !strncmp(buf, "on", 2))
0455         bd2802_enable_adv_conf(led);
0456     else if (led->adf_on && !strncmp(buf, "off", 3))
0457         bd2802_disable_adv_conf(led);
0458     up_write(&led->rwsem);
0459 
0460     return count;
0461 }
0462 
0463 static struct device_attribute bd2802_adv_conf_attr = {
0464     .attr = {
0465         .name = "advanced_configuration",
0466         .mode = 0644,
0467     },
0468     .show = bd2802_show_adv_conf,
0469     .store = bd2802_store_adv_conf,
0470 };
0471 
0472 #define BD2802_CONTROL_ATTR(attr_name, name_str)            \
0473 static ssize_t bd2802_show_##attr_name(struct device *dev,      \
0474     struct device_attribute *attr, char *buf)           \
0475 {                                   \
0476     struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
0477     ssize_t ret;                            \
0478     down_read(&led->rwsem);                     \
0479     ret = sprintf(buf, "0x%02x\n", led->attr_name);         \
0480     up_read(&led->rwsem);                       \
0481     return ret;                         \
0482 }                                   \
0483 static ssize_t bd2802_store_##attr_name(struct device *dev,     \
0484     struct device_attribute *attr, const char *buf, size_t count)   \
0485 {                                   \
0486     struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
0487     unsigned long val;                      \
0488     int ret;                            \
0489     if (!count)                         \
0490         return -EINVAL;                     \
0491     ret = kstrtoul(buf, 16, &val);                  \
0492     if (ret)                            \
0493         return ret;                     \
0494     down_write(&led->rwsem);                    \
0495     led->attr_name = val;                       \
0496     up_write(&led->rwsem);                      \
0497     return count;                           \
0498 }                                   \
0499 static struct device_attribute bd2802_##attr_name##_attr = {        \
0500     .attr = {                           \
0501         .name = name_str,                   \
0502         .mode = 0644,                       \
0503     },                              \
0504     .show = bd2802_show_##attr_name,                \
0505     .store = bd2802_store_##attr_name,              \
0506 };
0507 
0508 BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
0509 BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
0510 
0511 static struct device_attribute *bd2802_attributes[] = {
0512     &bd2802_adv_conf_attr,
0513     &bd2802_wave_pattern_attr,
0514     &bd2802_rgb_current_attr,
0515 };
0516 
0517 #define BD2802_CONTROL_RGBS(name, id, clr)              \
0518 static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
0519                     enum led_brightness value)  \
0520 {                                   \
0521     struct bd2802_led *led =                    \
0522         container_of(led_cdev, struct bd2802_led, cdev_##name); \
0523     led->led_id = id;                       \
0524     led->color = clr;                       \
0525     if (value == LED_OFF) {                     \
0526         led->state = BD2802_OFF;                \
0527         bd2802_turn_off(led, led->led_id, led->color);      \
0528     } else {                            \
0529         led->state = BD2802_ON;                 \
0530         bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
0531     }                               \
0532     return 0;                           \
0533 }                                   \
0534 static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
0535         unsigned long *delay_on, unsigned long *delay_off)  \
0536 {                                   \
0537     struct bd2802_led *led =                    \
0538         container_of(led_cdev, struct bd2802_led, cdev_##name); \
0539     if (*delay_on == 0 || *delay_off == 0)              \
0540         return -EINVAL;                     \
0541     led->led_id = id;                       \
0542     led->color = clr;                       \
0543     led->state = BD2802_BLINK;                  \
0544     bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK); \
0545     return 0;                           \
0546 }
0547 
0548 BD2802_CONTROL_RGBS(led1r, LED1, RED);
0549 BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
0550 BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
0551 BD2802_CONTROL_RGBS(led2r, LED2, RED);
0552 BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
0553 BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
0554 
0555 static int bd2802_register_led_classdev(struct bd2802_led *led)
0556 {
0557     int ret;
0558 
0559     led->cdev_led1r.name = "led1_R";
0560     led->cdev_led1r.brightness = LED_OFF;
0561     led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
0562     led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
0563 
0564     ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
0565     if (ret < 0) {
0566         dev_err(&led->client->dev, "couldn't register LED %s\n",
0567                             led->cdev_led1r.name);
0568         goto failed_unregister_led1_R;
0569     }
0570 
0571     led->cdev_led1g.name = "led1_G";
0572     led->cdev_led1g.brightness = LED_OFF;
0573     led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
0574     led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
0575 
0576     ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
0577     if (ret < 0) {
0578         dev_err(&led->client->dev, "couldn't register LED %s\n",
0579                             led->cdev_led1g.name);
0580         goto failed_unregister_led1_G;
0581     }
0582 
0583     led->cdev_led1b.name = "led1_B";
0584     led->cdev_led1b.brightness = LED_OFF;
0585     led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
0586     led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
0587 
0588     ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
0589     if (ret < 0) {
0590         dev_err(&led->client->dev, "couldn't register LED %s\n",
0591                             led->cdev_led1b.name);
0592         goto failed_unregister_led1_B;
0593     }
0594 
0595     led->cdev_led2r.name = "led2_R";
0596     led->cdev_led2r.brightness = LED_OFF;
0597     led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
0598     led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
0599 
0600     ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
0601     if (ret < 0) {
0602         dev_err(&led->client->dev, "couldn't register LED %s\n",
0603                             led->cdev_led2r.name);
0604         goto failed_unregister_led2_R;
0605     }
0606 
0607     led->cdev_led2g.name = "led2_G";
0608     led->cdev_led2g.brightness = LED_OFF;
0609     led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
0610     led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
0611 
0612     ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
0613     if (ret < 0) {
0614         dev_err(&led->client->dev, "couldn't register LED %s\n",
0615                             led->cdev_led2g.name);
0616         goto failed_unregister_led2_G;
0617     }
0618 
0619     led->cdev_led2b.name = "led2_B";
0620     led->cdev_led2b.brightness = LED_OFF;
0621     led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
0622     led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
0623     led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
0624 
0625     ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
0626     if (ret < 0) {
0627         dev_err(&led->client->dev, "couldn't register LED %s\n",
0628                             led->cdev_led2b.name);
0629         goto failed_unregister_led2_B;
0630     }
0631 
0632     return 0;
0633 
0634 failed_unregister_led2_B:
0635     led_classdev_unregister(&led->cdev_led2g);
0636 failed_unregister_led2_G:
0637     led_classdev_unregister(&led->cdev_led2r);
0638 failed_unregister_led2_R:
0639     led_classdev_unregister(&led->cdev_led1b);
0640 failed_unregister_led1_B:
0641     led_classdev_unregister(&led->cdev_led1g);
0642 failed_unregister_led1_G:
0643     led_classdev_unregister(&led->cdev_led1r);
0644 failed_unregister_led1_R:
0645 
0646     return ret;
0647 }
0648 
0649 static void bd2802_unregister_led_classdev(struct bd2802_led *led)
0650 {
0651     led_classdev_unregister(&led->cdev_led2b);
0652     led_classdev_unregister(&led->cdev_led2g);
0653     led_classdev_unregister(&led->cdev_led2r);
0654     led_classdev_unregister(&led->cdev_led1b);
0655     led_classdev_unregister(&led->cdev_led1g);
0656     led_classdev_unregister(&led->cdev_led1r);
0657 }
0658 
0659 static int bd2802_probe(struct i2c_client *client,
0660             const struct i2c_device_id *id)
0661 {
0662     struct bd2802_led *led;
0663     int ret, i;
0664 
0665     led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL);
0666     if (!led)
0667         return -ENOMEM;
0668 
0669     led->client = client;
0670     i2c_set_clientdata(client, led);
0671 
0672     /*
0673      * Configure RESET GPIO (L: RESET, H: RESET cancel)
0674      *
0675      * We request the reset GPIO as OUT_LOW which means de-asserted,
0676      * board files specifying this GPIO line in a machine descriptor
0677      * table should take care to specify GPIO_ACTIVE_LOW for this line.
0678      */
0679     led->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW);
0680     if (IS_ERR(led->reset))
0681         return PTR_ERR(led->reset);
0682 
0683     /* Tacss = min 0.1ms */
0684     udelay(100);
0685 
0686     /* Detect BD2802GU */
0687     ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
0688     if (ret < 0) {
0689         dev_err(&client->dev, "failed to detect device\n");
0690         return ret;
0691     } else
0692         dev_info(&client->dev, "return 0x%02x\n", ret);
0693 
0694     /* To save the power, reset BD2802 after detecting */
0695     gpiod_set_value(led->reset, 1);
0696 
0697     /* Default attributes */
0698     led->wave_pattern = BD2802_PATTERN_HALF;
0699     led->rgb_current = BD2802_CURRENT_032;
0700 
0701     init_rwsem(&led->rwsem);
0702 
0703     for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
0704         ret = device_create_file(&led->client->dev,
0705                         bd2802_attributes[i]);
0706         if (ret) {
0707             dev_err(&led->client->dev, "failed: sysfs file %s\n",
0708                     bd2802_attributes[i]->attr.name);
0709             goto failed_unregister_dev_file;
0710         }
0711     }
0712 
0713     ret = bd2802_register_led_classdev(led);
0714     if (ret < 0)
0715         goto failed_unregister_dev_file;
0716 
0717     return 0;
0718 
0719 failed_unregister_dev_file:
0720     for (i--; i >= 0; i--)
0721         device_remove_file(&led->client->dev, bd2802_attributes[i]);
0722     return ret;
0723 }
0724 
0725 static int bd2802_remove(struct i2c_client *client)
0726 {
0727     struct bd2802_led *led = i2c_get_clientdata(client);
0728     int i;
0729 
0730     gpiod_set_value(led->reset, 1);
0731     bd2802_unregister_led_classdev(led);
0732     if (led->adf_on)
0733         bd2802_disable_adv_conf(led);
0734     for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
0735         device_remove_file(&led->client->dev, bd2802_attributes[i]);
0736 
0737     return 0;
0738 }
0739 
0740 #ifdef CONFIG_PM_SLEEP
0741 static void bd2802_restore_state(struct bd2802_led *led)
0742 {
0743     int i;
0744 
0745     for (i = 0; i < LED_NUM; i++) {
0746         if (led->led[i].r)
0747             bd2802_turn_on(led, i, RED, led->led[i].r);
0748         if (led->led[i].g)
0749             bd2802_turn_on(led, i, GREEN, led->led[i].g);
0750         if (led->led[i].b)
0751             bd2802_turn_on(led, i, BLUE, led->led[i].b);
0752     }
0753 }
0754 
0755 static int bd2802_suspend(struct device *dev)
0756 {
0757     struct i2c_client *client = to_i2c_client(dev);
0758     struct bd2802_led *led = i2c_get_clientdata(client);
0759 
0760     gpiod_set_value(led->reset, 1);
0761 
0762     return 0;
0763 }
0764 
0765 static int bd2802_resume(struct device *dev)
0766 {
0767     struct i2c_client *client = to_i2c_client(dev);
0768     struct bd2802_led *led = i2c_get_clientdata(client);
0769 
0770     if (!bd2802_is_all_off(led) || led->adf_on) {
0771         bd2802_reset_cancel(led);
0772         bd2802_restore_state(led);
0773     }
0774 
0775     return 0;
0776 }
0777 #endif
0778 
0779 static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
0780 
0781 static const struct i2c_device_id bd2802_id[] = {
0782     { "BD2802", 0 },
0783     { }
0784 };
0785 MODULE_DEVICE_TABLE(i2c, bd2802_id);
0786 
0787 static struct i2c_driver bd2802_i2c_driver = {
0788     .driver = {
0789         .name   = "BD2802",
0790         .pm = &bd2802_pm,
0791     },
0792     .probe      = bd2802_probe,
0793     .remove     = bd2802_remove,
0794     .id_table   = bd2802_id,
0795 };
0796 
0797 module_i2c_driver(bd2802_i2c_driver);
0798 
0799 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
0800 MODULE_DESCRIPTION("BD2802 LED driver");
0801 MODULE_LICENSE("GPL v2");