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