linux/drivers/leds/leds-bd2802.c
<<
>>
Prefs
   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
  38enum led_ids {
  39        LED1,
  40        LED2,
  41        LED_NUM,
  42};
  43
  44enum led_colors {
  45        RED,
  46        GREEN,
  47        BLUE,
  48};
  49
  50enum 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 */
  61struct led_state {
  62        unsigned r:2;
  63        unsigned g:2;
  64        unsigned b:2;
  65};
  66
  67struct 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
 107static 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
 123static 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
 131static 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
 142static 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
 147static 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
 158static 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
 170static 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
 215static 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
 227static 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
 234static 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
 248static 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
 267static 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
 286static 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
 301static 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)                         \
 318static 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}                                                                       \
 334static struct device_attribute bd2802_reg##reg_addr##_attr = {          \
 335        .attr = {.name = reg_name, .mode = 0644},                       \
 336        .store = bd2802_store_reg##reg_addr,                            \
 337};
 338
 339BD2802_SET_REGISTER(0x00, "0x00");
 340BD2802_SET_REGISTER(0x01, "0x01");
 341BD2802_SET_REGISTER(0x02, "0x02");
 342BD2802_SET_REGISTER(0x03, "0x03");
 343BD2802_SET_REGISTER(0x04, "0x04");
 344BD2802_SET_REGISTER(0x05, "0x05");
 345BD2802_SET_REGISTER(0x06, "0x06");
 346BD2802_SET_REGISTER(0x07, "0x07");
 347BD2802_SET_REGISTER(0x08, "0x08");
 348BD2802_SET_REGISTER(0x09, "0x09");
 349BD2802_SET_REGISTER(0x0a, "0x0a");
 350BD2802_SET_REGISTER(0x0b, "0x0b");
 351BD2802_SET_REGISTER(0x0c, "0x0c");
 352BD2802_SET_REGISTER(0x0d, "0x0d");
 353BD2802_SET_REGISTER(0x0e, "0x0e");
 354BD2802_SET_REGISTER(0x0f, "0x0f");
 355BD2802_SET_REGISTER(0x10, "0x10");
 356BD2802_SET_REGISTER(0x11, "0x11");
 357BD2802_SET_REGISTER(0x12, "0x12");
 358BD2802_SET_REGISTER(0x13, "0x13");
 359BD2802_SET_REGISTER(0x14, "0x14");
 360BD2802_SET_REGISTER(0x15, "0x15");
 361
 362static 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
 387static 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
 408failed_remove_files:
 409        for (i--; i >= 0; i--)
 410                device_remove_file(&led->client->dev,
 411                                                bd2802_addr_attributes[i]);
 412}
 413
 414static 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
 428static 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
 444static 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
 462static 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)                        \
 472static 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}                                                                       \
 482static 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}                                                                       \
 498static 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
 507BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
 508BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
 509
 510static 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)                              \
 517static 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}                                                                       \
 533static 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
 547BD2802_CONTROL_RGBS(led1r, LED1, RED);
 548BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
 549BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
 550BD2802_CONTROL_RGBS(led2r, LED2, RED);
 551BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
 552BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
 553
 554static 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
 633failed_unregister_led2_B:
 634        led_classdev_unregister(&led->cdev_led2g);
 635failed_unregister_led2_G:
 636        led_classdev_unregister(&led->cdev_led2r);
 637failed_unregister_led2_R:
 638        led_classdev_unregister(&led->cdev_led1b);
 639failed_unregister_led1_B:
 640        led_classdev_unregister(&led->cdev_led1g);
 641failed_unregister_led1_G:
 642        led_classdev_unregister(&led->cdev_led1r);
 643failed_unregister_led1_R:
 644
 645        return ret;
 646}
 647
 648static 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
 658static 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
 712failed_unregister_dev_file:
 713        for (i--; i >= 0; i--)
 714                device_remove_file(&led->client->dev, bd2802_attributes[i]);
 715        return ret;
 716}
 717
 718static 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
 734static 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
 748static 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
 758static 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
 772static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
 773
 774static const struct i2c_device_id bd2802_id[] = {
 775        { "BD2802", 0 },
 776        { }
 777};
 778MODULE_DEVICE_TABLE(i2c, bd2802_id);
 779
 780static 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
 790module_i2c_driver(bd2802_i2c_driver);
 791
 792MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 793MODULE_DESCRIPTION("BD2802 LED driver");
 794MODULE_LICENSE("GPL v2");
 795