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