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