root/drivers/leds/leds-bd2802.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bd2802_is_rgb_off
  2. bd2802_is_led_off
  3. bd2802_is_all_off
  4. bd2802_get_base_offset
  5. bd2802_get_reg_addr
  6. bd2802_write_byte
  7. bd2802_update_state
  8. bd2802_configure
  9. bd2802_reset_cancel
  10. bd2802_enable
  11. bd2802_set_on
  12. bd2802_set_blink
  13. bd2802_turn_on
  14. bd2802_turn_off
  15. bd2802_enable_adv_conf
  16. bd2802_disable_adv_conf
  17. bd2802_show_adv_conf
  18. bd2802_store_adv_conf
  19. bd2802_register_led_classdev
  20. bd2802_unregister_led_classdev
  21. bd2802_probe
  22. bd2802_remove
  23. bd2802_restore_state
  24. bd2802_suspend
  25. bd2802_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * leds-bd2802.c - RGB LED Driver
   4  *
   5  * Copyright (C) 2009 Samsung Electronics
   6  * Kim Kyuwon <q1.kim@samsung.com>
   7  *
   8  * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
   9  */
  10 
  11 #include <linux/module.h>
  12 #include <linux/i2c.h>
  13 #include <linux/gpio.h>
  14 #include <linux/delay.h>
  15 #include <linux/leds.h>
  16 #include <linux/leds-bd2802.h>
  17 #include <linux/slab.h>
  18 #include <linux/pm.h>
  19 
  20 #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
  21 
  22 #define BD2802_LED_OFFSET               0xa
  23 #define BD2802_COLOR_OFFSET             0x3
  24 
  25 #define BD2802_REG_CLKSETUP             0x00
  26 #define BD2802_REG_CONTROL              0x01
  27 #define BD2802_REG_HOURSETUP            0x02
  28 #define BD2802_REG_CURRENT1SETUP        0x03
  29 #define BD2802_REG_CURRENT2SETUP        0x04
  30 #define BD2802_REG_WAVEPATTERN          0x05
  31 
  32 #define BD2802_CURRENT_032              0x10 /* 3.2mA */
  33 #define BD2802_CURRENT_000              0x00 /* 0.0mA */
  34 
  35 #define BD2802_PATTERN_FULL             0x07
  36 #define BD2802_PATTERN_HALF             0x03
  37 
  38 enum led_ids {
  39         LED1,
  40         LED2,
  41         LED_NUM,
  42 };
  43 
  44 enum led_colors {
  45         RED,
  46         GREEN,
  47         BLUE,
  48 };
  49 
  50 enum led_bits {
  51         BD2802_OFF,
  52         BD2802_BLINK,
  53         BD2802_ON,
  54 };
  55 
  56 /*
  57  * State '0' : 'off'
  58  * State '1' : 'blink'
  59  * State '2' : 'on'.
  60  */
  61 struct led_state {
  62         unsigned r:2;
  63         unsigned g:2;
  64         unsigned b:2;
  65 };
  66 
  67 struct bd2802_led {
  68         struct bd2802_led_platform_data *pdata;
  69         struct i2c_client               *client;
  70         struct rw_semaphore             rwsem;
  71 
  72         struct led_state                led[2];
  73 
  74         /*
  75          * Making led_classdev as array is not recommended, because array
  76          * members prevent using 'container_of' macro. So repetitive works
  77          * are needed.
  78          */
  79         struct led_classdev             cdev_led1r;
  80         struct led_classdev             cdev_led1g;
  81         struct led_classdev             cdev_led1b;
  82         struct led_classdev             cdev_led2r;
  83         struct led_classdev             cdev_led2g;
  84         struct led_classdev             cdev_led2b;
  85 
  86         /*
  87          * Advanced Configuration Function(ADF) mode:
  88          * In ADF mode, user can set registers of BD2802GU directly,
  89          * therefore BD2802GU doesn't enter reset state.
  90          */
  91         int                             adf_on;
  92 
  93         enum led_ids                    led_id;
  94         enum led_colors                 color;
  95         enum led_bits                   state;
  96 
  97         /* General attributes of RGB LEDs */
  98         int                             wave_pattern;
  99         int                             rgb_current;
 100 };
 101 
 102 
 103 /*--------------------------------------------------------------*/
 104 /*      BD2802GU helper functions                                       */
 105 /*--------------------------------------------------------------*/
 106 
 107 static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
 108                                                         enum led_colors color)
 109 {
 110         switch (color) {
 111         case RED:
 112                 return !led->led[id].r;
 113         case GREEN:
 114                 return !led->led[id].g;
 115         case BLUE:
 116                 return !led->led[id].b;
 117         default:
 118                 dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
 119                 return -EINVAL;
 120         }
 121 }
 122 
 123 static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
 124 {
 125         if (led->led[id].r || led->led[id].g || led->led[id].b)
 126                 return 0;
 127 
 128         return 1;
 129 }
 130 
 131 static inline int bd2802_is_all_off(struct bd2802_led *led)
 132 {
 133         int i;
 134 
 135         for (i = 0; i < LED_NUM; i++)
 136                 if (!bd2802_is_led_off(led, i))
 137                         return 0;
 138 
 139         return 1;
 140 }
 141 
 142 static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
 143 {
 144         return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
 145 }
 146 
 147 static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
 148                                                                 u8 reg_offset)
 149 {
 150         return reg_offset + bd2802_get_base_offset(id, color);
 151 }
 152 
 153 
 154 /*--------------------------------------------------------------*/
 155 /*      BD2802GU core functions                                 */
 156 /*--------------------------------------------------------------*/
 157 
 158 static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
 159 {
 160         int ret = i2c_smbus_write_byte_data(client, reg, val);
 161         if (ret >= 0)
 162                 return 0;
 163 
 164         dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
 165                                                 __func__, reg, val, ret);
 166 
 167         return ret;
 168 }
 169 
 170 static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
 171                                 enum led_colors color, enum led_bits led_bit)
 172 {
 173         int i;
 174         u8 value;
 175 
 176         for (i = 0; i < LED_NUM; i++) {
 177                 if (i == id) {
 178                         switch (color) {
 179                         case RED:
 180                                 led->led[i].r = led_bit;
 181                                 break;
 182                         case GREEN:
 183                                 led->led[i].g = led_bit;
 184                                 break;
 185                         case BLUE:
 186                                 led->led[i].b = led_bit;
 187                                 break;
 188                         default:
 189                                 dev_err(&led->client->dev,
 190                                         "%s: Invalid color\n", __func__);
 191                                 return;
 192                         }
 193                 }
 194         }
 195 
 196         if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
 197                 return;
 198 
 199         if (!bd2802_is_led_off(led, id))
 200                 return;
 201 
 202         if (bd2802_is_all_off(led) && !led->adf_on) {
 203                 gpio_set_value(led->pdata->reset_gpio, 0);
 204                 return;
 205         }
 206 
 207         /*
 208          * In this case, other led is turned on, and current led is turned
 209          * off. So set RGB LED Control register to stop the current RGB LED
 210          */
 211         value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
 212         bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
 213 }
 214 
 215 static void bd2802_configure(struct bd2802_led *led)
 216 {
 217         struct bd2802_led_platform_data *pdata = led->pdata;
 218         u8 reg;
 219 
 220         reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
 221         bd2802_write_byte(led->client, reg, pdata->rgb_time);
 222 
 223         reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
 224         bd2802_write_byte(led->client, reg, pdata->rgb_time);
 225 }
 226 
 227 static void bd2802_reset_cancel(struct bd2802_led *led)
 228 {
 229         gpio_set_value(led->pdata->reset_gpio, 1);
 230         udelay(100);
 231         bd2802_configure(led);
 232 }
 233 
 234 static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
 235 {
 236         enum led_ids other_led = (id == LED1) ? LED2 : LED1;
 237         u8 value, other_led_on;
 238 
 239         other_led_on = !bd2802_is_led_off(led, other_led);
 240         if (id == LED1)
 241                 value = LED_CTL(other_led_on, 1);
 242         else
 243                 value = LED_CTL(1 , other_led_on);
 244 
 245         bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
 246 }
 247 
 248 static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
 249                                                         enum led_colors color)
 250 {
 251         u8 reg;
 252 
 253         if (bd2802_is_all_off(led) && !led->adf_on)
 254                 bd2802_reset_cancel(led);
 255 
 256         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
 257         bd2802_write_byte(led->client, reg, led->rgb_current);
 258         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
 259         bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
 260         reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
 261         bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
 262 
 263         bd2802_enable(led, id);
 264         bd2802_update_state(led, id, color, BD2802_ON);
 265 }
 266 
 267 static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
 268                                                         enum led_colors color)
 269 {
 270         u8 reg;
 271 
 272         if (bd2802_is_all_off(led) && !led->adf_on)
 273                 bd2802_reset_cancel(led);
 274 
 275         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
 276         bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
 277         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
 278         bd2802_write_byte(led->client, reg, led->rgb_current);
 279         reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
 280         bd2802_write_byte(led->client, reg, led->wave_pattern);
 281 
 282         bd2802_enable(led, id);
 283         bd2802_update_state(led, id, color, BD2802_BLINK);
 284 }
 285 
 286 static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
 287                                 enum led_colors color, enum led_bits led_bit)
 288 {
 289         if (led_bit == BD2802_OFF) {
 290                 dev_err(&led->client->dev,
 291                                         "Only 'blink' and 'on' are allowed\n");
 292                 return;
 293         }
 294 
 295         if (led_bit == BD2802_BLINK)
 296                 bd2802_set_blink(led, id, color);
 297         else
 298                 bd2802_set_on(led, id, color);
 299 }
 300 
 301 static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
 302                                                         enum led_colors color)
 303 {
 304         u8 reg;
 305 
 306         if (bd2802_is_rgb_off(led, id, color))
 307                 return;
 308 
 309         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
 310         bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
 311         reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
 312         bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
 313 
 314         bd2802_update_state(led, id, color, BD2802_OFF);
 315 }
 316 
 317 #define BD2802_SET_REGISTER(reg_addr, reg_name)                         \
 318 static ssize_t bd2802_store_reg##reg_addr(struct device *dev,           \
 319         struct device_attribute *attr, const char *buf, size_t count)   \
 320 {                                                                       \
 321         struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
 322         unsigned long val;                                              \
 323         int ret;                                                        \
 324         if (!count)                                                     \
 325                 return -EINVAL;                                         \
 326         ret = kstrtoul(buf, 16, &val);                                  \
 327         if (ret)                                                        \
 328                 return ret;                                             \
 329         down_write(&led->rwsem);                                        \
 330         bd2802_write_byte(led->client, reg_addr, (u8) val);             \
 331         up_write(&led->rwsem);                                          \
 332         return count;                                                   \
 333 }                                                                       \
 334 static struct device_attribute bd2802_reg##reg_addr##_attr = {          \
 335         .attr = {.name = reg_name, .mode = 0644},                       \
 336         .store = bd2802_store_reg##reg_addr,                            \
 337 };
 338 
 339 BD2802_SET_REGISTER(0x00, "0x00");
 340 BD2802_SET_REGISTER(0x01, "0x01");
 341 BD2802_SET_REGISTER(0x02, "0x02");
 342 BD2802_SET_REGISTER(0x03, "0x03");
 343 BD2802_SET_REGISTER(0x04, "0x04");
 344 BD2802_SET_REGISTER(0x05, "0x05");
 345 BD2802_SET_REGISTER(0x06, "0x06");
 346 BD2802_SET_REGISTER(0x07, "0x07");
 347 BD2802_SET_REGISTER(0x08, "0x08");
 348 BD2802_SET_REGISTER(0x09, "0x09");
 349 BD2802_SET_REGISTER(0x0a, "0x0a");
 350 BD2802_SET_REGISTER(0x0b, "0x0b");
 351 BD2802_SET_REGISTER(0x0c, "0x0c");
 352 BD2802_SET_REGISTER(0x0d, "0x0d");
 353 BD2802_SET_REGISTER(0x0e, "0x0e");
 354 BD2802_SET_REGISTER(0x0f, "0x0f");
 355 BD2802_SET_REGISTER(0x10, "0x10");
 356 BD2802_SET_REGISTER(0x11, "0x11");
 357 BD2802_SET_REGISTER(0x12, "0x12");
 358 BD2802_SET_REGISTER(0x13, "0x13");
 359 BD2802_SET_REGISTER(0x14, "0x14");
 360 BD2802_SET_REGISTER(0x15, "0x15");
 361 
 362 static struct device_attribute *bd2802_addr_attributes[] = {
 363         &bd2802_reg0x00_attr,
 364         &bd2802_reg0x01_attr,
 365         &bd2802_reg0x02_attr,
 366         &bd2802_reg0x03_attr,
 367         &bd2802_reg0x04_attr,
 368         &bd2802_reg0x05_attr,
 369         &bd2802_reg0x06_attr,
 370         &bd2802_reg0x07_attr,
 371         &bd2802_reg0x08_attr,
 372         &bd2802_reg0x09_attr,
 373         &bd2802_reg0x0a_attr,
 374         &bd2802_reg0x0b_attr,
 375         &bd2802_reg0x0c_attr,
 376         &bd2802_reg0x0d_attr,
 377         &bd2802_reg0x0e_attr,
 378         &bd2802_reg0x0f_attr,
 379         &bd2802_reg0x10_attr,
 380         &bd2802_reg0x11_attr,
 381         &bd2802_reg0x12_attr,
 382         &bd2802_reg0x13_attr,
 383         &bd2802_reg0x14_attr,
 384         &bd2802_reg0x15_attr,
 385 };
 386 
 387 static void bd2802_enable_adv_conf(struct bd2802_led *led)
 388 {
 389         int i, ret;
 390 
 391         for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
 392                 ret = device_create_file(&led->client->dev,
 393                                                 bd2802_addr_attributes[i]);
 394                 if (ret) {
 395                         dev_err(&led->client->dev, "failed: sysfs file %s\n",
 396                                         bd2802_addr_attributes[i]->attr.name);
 397                         goto failed_remove_files;
 398                 }
 399         }
 400 
 401         if (bd2802_is_all_off(led))
 402                 bd2802_reset_cancel(led);
 403 
 404         led->adf_on = 1;
 405 
 406         return;
 407 
 408 failed_remove_files:
 409         for (i--; i >= 0; i--)
 410                 device_remove_file(&led->client->dev,
 411                                                 bd2802_addr_attributes[i]);
 412 }
 413 
 414 static void bd2802_disable_adv_conf(struct bd2802_led *led)
 415 {
 416         int i;
 417 
 418         for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
 419                 device_remove_file(&led->client->dev,
 420                                                 bd2802_addr_attributes[i]);
 421 
 422         if (bd2802_is_all_off(led))
 423                 gpio_set_value(led->pdata->reset_gpio, 0);
 424 
 425         led->adf_on = 0;
 426 }
 427 
 428 static ssize_t bd2802_show_adv_conf(struct device *dev,
 429         struct device_attribute *attr, char *buf)
 430 {
 431         struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
 432         ssize_t ret;
 433 
 434         down_read(&led->rwsem);
 435         if (led->adf_on)
 436                 ret = sprintf(buf, "on\n");
 437         else
 438                 ret = sprintf(buf, "off\n");
 439         up_read(&led->rwsem);
 440 
 441         return ret;
 442 }
 443 
 444 static ssize_t bd2802_store_adv_conf(struct device *dev,
 445         struct device_attribute *attr, const char *buf, size_t count)
 446 {
 447         struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
 448 
 449         if (!count)
 450                 return -EINVAL;
 451 
 452         down_write(&led->rwsem);
 453         if (!led->adf_on && !strncmp(buf, "on", 2))
 454                 bd2802_enable_adv_conf(led);
 455         else if (led->adf_on && !strncmp(buf, "off", 3))
 456                 bd2802_disable_adv_conf(led);
 457         up_write(&led->rwsem);
 458 
 459         return count;
 460 }
 461 
 462 static struct device_attribute bd2802_adv_conf_attr = {
 463         .attr = {
 464                 .name = "advanced_configuration",
 465                 .mode = 0644,
 466         },
 467         .show = bd2802_show_adv_conf,
 468         .store = bd2802_store_adv_conf,
 469 };
 470 
 471 #define BD2802_CONTROL_ATTR(attr_name, name_str)                        \
 472 static ssize_t bd2802_show_##attr_name(struct device *dev,              \
 473         struct device_attribute *attr, char *buf)                       \
 474 {                                                                       \
 475         struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
 476         ssize_t ret;                                                    \
 477         down_read(&led->rwsem);                                         \
 478         ret = sprintf(buf, "0x%02x\n", led->attr_name);                 \
 479         up_read(&led->rwsem);                                           \
 480         return ret;                                                     \
 481 }                                                                       \
 482 static ssize_t bd2802_store_##attr_name(struct device *dev,             \
 483         struct device_attribute *attr, const char *buf, size_t count)   \
 484 {                                                                       \
 485         struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
 486         unsigned long val;                                              \
 487         int ret;                                                        \
 488         if (!count)                                                     \
 489                 return -EINVAL;                                         \
 490         ret = kstrtoul(buf, 16, &val);                                  \
 491         if (ret)                                                        \
 492                 return ret;                                             \
 493         down_write(&led->rwsem);                                        \
 494         led->attr_name = val;                                           \
 495         up_write(&led->rwsem);                                          \
 496         return count;                                                   \
 497 }                                                                       \
 498 static struct device_attribute bd2802_##attr_name##_attr = {            \
 499         .attr = {                                                       \
 500                 .name = name_str,                                       \
 501                 .mode = 0644,                                           \
 502         },                                                              \
 503         .show = bd2802_show_##attr_name,                                \
 504         .store = bd2802_store_##attr_name,                              \
 505 };
 506 
 507 BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
 508 BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
 509 
 510 static struct device_attribute *bd2802_attributes[] = {
 511         &bd2802_adv_conf_attr,
 512         &bd2802_wave_pattern_attr,
 513         &bd2802_rgb_current_attr,
 514 };
 515 
 516 #define BD2802_CONTROL_RGBS(name, id, clr)                              \
 517 static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
 518                                         enum led_brightness value)      \
 519 {                                                                       \
 520         struct bd2802_led *led =                                        \
 521                 container_of(led_cdev, struct bd2802_led, cdev_##name); \
 522         led->led_id = id;                                               \
 523         led->color = clr;                                               \
 524         if (value == LED_OFF) {                                         \
 525                 led->state = BD2802_OFF;                                \
 526                 bd2802_turn_off(led, led->led_id, led->color);          \
 527         } else {                                                        \
 528                 led->state = BD2802_ON;                                 \
 529                 bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
 530         }                                                               \
 531         return 0;                                                       \
 532 }                                                                       \
 533 static int bd2802_set_##name##_blink(struct led_classdev *led_cdev,     \
 534                 unsigned long *delay_on, unsigned long *delay_off)      \
 535 {                                                                       \
 536         struct bd2802_led *led =                                        \
 537                 container_of(led_cdev, struct bd2802_led, cdev_##name); \
 538         if (*delay_on == 0 || *delay_off == 0)                          \
 539                 return -EINVAL;                                         \
 540         led->led_id = id;                                               \
 541         led->color = clr;                                               \
 542         led->state = BD2802_BLINK;                                      \
 543         bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK);     \
 544         return 0;                                                       \
 545 }
 546 
 547 BD2802_CONTROL_RGBS(led1r, LED1, RED);
 548 BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
 549 BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
 550 BD2802_CONTROL_RGBS(led2r, LED2, RED);
 551 BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
 552 BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
 553 
 554 static int bd2802_register_led_classdev(struct bd2802_led *led)
 555 {
 556         int ret;
 557 
 558         led->cdev_led1r.name = "led1_R";
 559         led->cdev_led1r.brightness = LED_OFF;
 560         led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
 561         led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
 562 
 563         ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
 564         if (ret < 0) {
 565                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 566                                                         led->cdev_led1r.name);
 567                 goto failed_unregister_led1_R;
 568         }
 569 
 570         led->cdev_led1g.name = "led1_G";
 571         led->cdev_led1g.brightness = LED_OFF;
 572         led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
 573         led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
 574 
 575         ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
 576         if (ret < 0) {
 577                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 578                                                         led->cdev_led1g.name);
 579                 goto failed_unregister_led1_G;
 580         }
 581 
 582         led->cdev_led1b.name = "led1_B";
 583         led->cdev_led1b.brightness = LED_OFF;
 584         led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
 585         led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
 586 
 587         ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
 588         if (ret < 0) {
 589                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 590                                                         led->cdev_led1b.name);
 591                 goto failed_unregister_led1_B;
 592         }
 593 
 594         led->cdev_led2r.name = "led2_R";
 595         led->cdev_led2r.brightness = LED_OFF;
 596         led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
 597         led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
 598 
 599         ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
 600         if (ret < 0) {
 601                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 602                                                         led->cdev_led2r.name);
 603                 goto failed_unregister_led2_R;
 604         }
 605 
 606         led->cdev_led2g.name = "led2_G";
 607         led->cdev_led2g.brightness = LED_OFF;
 608         led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
 609         led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
 610 
 611         ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
 612         if (ret < 0) {
 613                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 614                                                         led->cdev_led2g.name);
 615                 goto failed_unregister_led2_G;
 616         }
 617 
 618         led->cdev_led2b.name = "led2_B";
 619         led->cdev_led2b.brightness = LED_OFF;
 620         led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
 621         led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
 622         led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
 623 
 624         ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
 625         if (ret < 0) {
 626                 dev_err(&led->client->dev, "couldn't register LED %s\n",
 627                                                         led->cdev_led2b.name);
 628                 goto failed_unregister_led2_B;
 629         }
 630 
 631         return 0;
 632 
 633 failed_unregister_led2_B:
 634         led_classdev_unregister(&led->cdev_led2g);
 635 failed_unregister_led2_G:
 636         led_classdev_unregister(&led->cdev_led2r);
 637 failed_unregister_led2_R:
 638         led_classdev_unregister(&led->cdev_led1b);
 639 failed_unregister_led1_B:
 640         led_classdev_unregister(&led->cdev_led1g);
 641 failed_unregister_led1_G:
 642         led_classdev_unregister(&led->cdev_led1r);
 643 failed_unregister_led1_R:
 644 
 645         return ret;
 646 }
 647 
 648 static void bd2802_unregister_led_classdev(struct bd2802_led *led)
 649 {
 650         led_classdev_unregister(&led->cdev_led2b);
 651         led_classdev_unregister(&led->cdev_led2g);
 652         led_classdev_unregister(&led->cdev_led2r);
 653         led_classdev_unregister(&led->cdev_led1b);
 654         led_classdev_unregister(&led->cdev_led1g);
 655         led_classdev_unregister(&led->cdev_led1r);
 656 }
 657 
 658 static int bd2802_probe(struct i2c_client *client,
 659                         const struct i2c_device_id *id)
 660 {
 661         struct bd2802_led *led;
 662         struct bd2802_led_platform_data *pdata;
 663         int ret, i;
 664 
 665         led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL);
 666         if (!led)
 667                 return -ENOMEM;
 668 
 669         led->client = client;
 670         pdata = led->pdata = dev_get_platdata(&client->dev);
 671         i2c_set_clientdata(client, led);
 672 
 673         /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
 674         gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH, "RGB_RESETB");
 675 
 676         /* Tacss = min 0.1ms */
 677         udelay(100);
 678 
 679         /* Detect BD2802GU */
 680         ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
 681         if (ret < 0) {
 682                 dev_err(&client->dev, "failed to detect device\n");
 683                 return ret;
 684         } else
 685                 dev_info(&client->dev, "return 0x%02x\n", ret);
 686 
 687         /* To save the power, reset BD2802 after detecting */
 688         gpio_set_value(led->pdata->reset_gpio, 0);
 689 
 690         /* Default attributes */
 691         led->wave_pattern = BD2802_PATTERN_HALF;
 692         led->rgb_current = BD2802_CURRENT_032;
 693 
 694         init_rwsem(&led->rwsem);
 695 
 696         for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
 697                 ret = device_create_file(&led->client->dev,
 698                                                 bd2802_attributes[i]);
 699                 if (ret) {
 700                         dev_err(&led->client->dev, "failed: sysfs file %s\n",
 701                                         bd2802_attributes[i]->attr.name);
 702                         goto failed_unregister_dev_file;
 703                 }
 704         }
 705 
 706         ret = bd2802_register_led_classdev(led);
 707         if (ret < 0)
 708                 goto failed_unregister_dev_file;
 709 
 710         return 0;
 711 
 712 failed_unregister_dev_file:
 713         for (i--; i >= 0; i--)
 714                 device_remove_file(&led->client->dev, bd2802_attributes[i]);
 715         return ret;
 716 }
 717 
 718 static int bd2802_remove(struct i2c_client *client)
 719 {
 720         struct bd2802_led *led = i2c_get_clientdata(client);
 721         int i;
 722 
 723         gpio_set_value(led->pdata->reset_gpio, 0);
 724         bd2802_unregister_led_classdev(led);
 725         if (led->adf_on)
 726                 bd2802_disable_adv_conf(led);
 727         for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
 728                 device_remove_file(&led->client->dev, bd2802_attributes[i]);
 729 
 730         return 0;
 731 }
 732 
 733 #ifdef CONFIG_PM_SLEEP
 734 static void bd2802_restore_state(struct bd2802_led *led)
 735 {
 736         int i;
 737 
 738         for (i = 0; i < LED_NUM; i++) {
 739                 if (led->led[i].r)
 740                         bd2802_turn_on(led, i, RED, led->led[i].r);
 741                 if (led->led[i].g)
 742                         bd2802_turn_on(led, i, GREEN, led->led[i].g);
 743                 if (led->led[i].b)
 744                         bd2802_turn_on(led, i, BLUE, led->led[i].b);
 745         }
 746 }
 747 
 748 static int bd2802_suspend(struct device *dev)
 749 {
 750         struct i2c_client *client = to_i2c_client(dev);
 751         struct bd2802_led *led = i2c_get_clientdata(client);
 752 
 753         gpio_set_value(led->pdata->reset_gpio, 0);
 754 
 755         return 0;
 756 }
 757 
 758 static int bd2802_resume(struct device *dev)
 759 {
 760         struct i2c_client *client = to_i2c_client(dev);
 761         struct bd2802_led *led = i2c_get_clientdata(client);
 762 
 763         if (!bd2802_is_all_off(led) || led->adf_on) {
 764                 bd2802_reset_cancel(led);
 765                 bd2802_restore_state(led);
 766         }
 767 
 768         return 0;
 769 }
 770 #endif
 771 
 772 static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
 773 
 774 static const struct i2c_device_id bd2802_id[] = {
 775         { "BD2802", 0 },
 776         { }
 777 };
 778 MODULE_DEVICE_TABLE(i2c, bd2802_id);
 779 
 780 static struct i2c_driver bd2802_i2c_driver = {
 781         .driver = {
 782                 .name   = "BD2802",
 783                 .pm     = &bd2802_pm,
 784         },
 785         .probe          = bd2802_probe,
 786         .remove         = bd2802_remove,
 787         .id_table       = bd2802_id,
 788 };
 789 
 790 module_i2c_driver(bd2802_i2c_driver);
 791 
 792 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 793 MODULE_DESCRIPTION("BD2802 LED driver");
 794 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */