linux/drivers/leds/leds-blinkm.c
<<
>>
Prefs
   1/*
   2 *  leds-blinkm.c
   3 *  (c) Jan-Simon Möller (dl9pf@gmx.de)
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License as published by
   7 *  the Free Software Foundation; either version 2 of the License, or
   8 *  (at your option) any later version.
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, write to the Free Software
  17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/slab.h>
  22#include <linux/jiffies.h>
  23#include <linux/i2c.h>
  24#include <linux/err.h>
  25#include <linux/mutex.h>
  26#include <linux/sysfs.h>
  27#include <linux/printk.h>
  28#include <linux/pm_runtime.h>
  29#include <linux/leds.h>
  30#include <linux/delay.h>
  31
  32/* Addresses to scan - BlinkM is on 0x09 by default*/
  33static const unsigned short normal_i2c[] = { 0x09, I2C_CLIENT_END };
  34
  35static int blinkm_transfer_hw(struct i2c_client *client, int cmd);
  36static int blinkm_test_run(struct i2c_client *client);
  37
  38struct blinkm_led {
  39        struct i2c_client *i2c_client;
  40        struct led_classdev led_cdev;
  41        int id;
  42};
  43
  44#define cdev_to_blmled(c)          container_of(c, struct blinkm_led, led_cdev)
  45
  46struct blinkm_data {
  47        struct i2c_client *i2c_client;
  48        struct mutex update_lock;
  49        /* used for led class interface */
  50        struct blinkm_led blinkm_leds[3];
  51        /* used for "blinkm" sysfs interface */
  52        u8 red;                 /* color red */
  53        u8 green;               /* color green */
  54        u8 blue;                /* color blue */
  55        /* next values to use for transfer */
  56        u8 next_red;                    /* color red */
  57        u8 next_green;          /* color green */
  58        u8 next_blue;           /* color blue */
  59        /* internal use */
  60        u8 args[7];             /* set of args for transmission */
  61        u8 i2c_addr;            /* i2c addr */
  62        u8 fw_ver;              /* firmware version */
  63        /* used, but not from userspace */
  64        u8 hue;                 /* HSB  hue */
  65        u8 saturation;          /* HSB  saturation */
  66        u8 brightness;          /* HSB  brightness */
  67        u8 next_hue;                    /* HSB  hue */
  68        u8 next_saturation;             /* HSB  saturation */
  69        u8 next_brightness;             /* HSB  brightness */
  70        /* currently unused / todo */
  71        u8 fade_speed;          /* fade speed     1 - 255 */
  72        s8 time_adjust;         /* time adjust -128 - 127 */
  73        u8 fade:1;              /* fade on = 1, off = 0 */
  74        u8 rand:1;              /* rand fade mode on = 1 */
  75        u8 script_id;           /* script ID */
  76        u8 script_repeats;      /* repeats of script */
  77        u8 script_startline;    /* line to start */
  78};
  79
  80/* Colors */
  81#define RED   0
  82#define GREEN 1
  83#define BLUE  2
  84
  85/* mapping command names to cmd chars - see datasheet */
  86#define BLM_GO_RGB            0
  87#define BLM_FADE_RGB          1
  88#define BLM_FADE_HSB          2
  89#define BLM_FADE_RAND_RGB     3
  90#define BLM_FADE_RAND_HSB     4
  91#define BLM_PLAY_SCRIPT       5
  92#define BLM_STOP_SCRIPT       6
  93#define BLM_SET_FADE_SPEED    7
  94#define BLM_SET_TIME_ADJ      8
  95#define BLM_GET_CUR_RGB       9
  96#define BLM_WRITE_SCRIPT_LINE 10
  97#define BLM_READ_SCRIPT_LINE  11
  98#define BLM_SET_SCRIPT_LR     12        /* Length & Repeats */
  99#define BLM_SET_ADDR          13
 100#define BLM_GET_ADDR          14
 101#define BLM_GET_FW_VER        15
 102#define BLM_SET_STARTUP_PARAM 16
 103
 104/* BlinkM Commands
 105 *  as extracted out of the datasheet:
 106 *
 107 *  cmdchar = command (ascii)
 108 *  cmdbyte = command in hex
 109 *  nr_args = number of arguments (to send)
 110 *  nr_ret  = number of return values (to read)
 111 *  dir = direction (0 = read, 1 = write, 2 = both)
 112 *
 113 */
 114static const struct {
 115        char cmdchar;
 116        u8 cmdbyte;
 117        u8 nr_args;
 118        u8 nr_ret;
 119        u8 dir:2;
 120} blinkm_cmds[17] = {
 121  /* cmdchar, cmdbyte, nr_args, nr_ret,  dir */
 122        { 'n', 0x6e, 3, 0, 1},
 123        { 'c', 0x63, 3, 0, 1},
 124        { 'h', 0x68, 3, 0, 1},
 125        { 'C', 0x43, 3, 0, 1},
 126        { 'H', 0x48, 3, 0, 1},
 127        { 'p', 0x70, 3, 0, 1},
 128        { 'o', 0x6f, 0, 0, 1},
 129        { 'f', 0x66, 1, 0, 1},
 130        { 't', 0x74, 1, 0, 1},
 131        { 'g', 0x67, 0, 3, 0},
 132        { 'W', 0x57, 7, 0, 1},
 133        { 'R', 0x52, 2, 5, 2},
 134        { 'L', 0x4c, 3, 0, 1},
 135        { 'A', 0x41, 4, 0, 1},
 136        { 'a', 0x61, 0, 1, 0},
 137        { 'Z', 0x5a, 0, 1, 0},
 138        { 'B', 0x42, 5, 0, 1},
 139};
 140
 141static ssize_t show_color_common(struct device *dev, char *buf, int color)
 142{
 143        struct i2c_client *client;
 144        struct blinkm_data *data;
 145        int ret;
 146
 147        client = to_i2c_client(dev);
 148        data = i2c_get_clientdata(client);
 149
 150        ret = blinkm_transfer_hw(client, BLM_GET_CUR_RGB);
 151        if (ret < 0)
 152                return ret;
 153        switch (color) {
 154        case RED:
 155                return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red);
 156        case GREEN:
 157                return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green);
 158        case BLUE:
 159                return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue);
 160        default:
 161                return -EINVAL;
 162        }
 163        return -EINVAL;
 164}
 165
 166static int store_color_common(struct device *dev, const char *buf, int color)
 167{
 168        struct i2c_client *client;
 169        struct blinkm_data *data;
 170        int ret;
 171        u8 value;
 172
 173        client = to_i2c_client(dev);
 174        data = i2c_get_clientdata(client);
 175
 176        ret = kstrtou8(buf, 10, &value);
 177        if (ret < 0) {
 178                dev_err(dev, "BlinkM: value too large!\n");
 179                return ret;
 180        }
 181
 182        switch (color) {
 183        case RED:
 184                data->next_red = value;
 185                break;
 186        case GREEN:
 187                data->next_green = value;
 188                break;
 189        case BLUE:
 190                data->next_blue = value;
 191                break;
 192        default:
 193                return -EINVAL;
 194        }
 195
 196        dev_dbg(dev, "next_red = %d, next_green = %d, next_blue = %d\n",
 197                        data->next_red, data->next_green, data->next_blue);
 198
 199        /* if mode ... */
 200        ret = blinkm_transfer_hw(client, BLM_GO_RGB);
 201        if (ret < 0) {
 202                dev_err(dev, "BlinkM: can't set RGB\n");
 203                return ret;
 204        }
 205        return 0;
 206}
 207
 208static ssize_t show_red(struct device *dev, struct device_attribute *attr,
 209                        char *buf)
 210{
 211        return show_color_common(dev, buf, RED);
 212}
 213
 214static ssize_t store_red(struct device *dev, struct device_attribute *attr,
 215                         const char *buf, size_t count)
 216{
 217        int ret;
 218
 219        ret = store_color_common(dev, buf, RED);
 220        if (ret < 0)
 221                return ret;
 222        return count;
 223}
 224
 225static DEVICE_ATTR(red, S_IRUGO | S_IWUSR, show_red, store_red);
 226
 227static ssize_t show_green(struct device *dev, struct device_attribute *attr,
 228                          char *buf)
 229{
 230        return show_color_common(dev, buf, GREEN);
 231}
 232
 233static ssize_t store_green(struct device *dev, struct device_attribute *attr,
 234                           const char *buf, size_t count)
 235{
 236
 237        int ret;
 238
 239        ret = store_color_common(dev, buf, GREEN);
 240        if (ret < 0)
 241                return ret;
 242        return count;
 243}
 244
 245static DEVICE_ATTR(green, S_IRUGO | S_IWUSR, show_green, store_green);
 246
 247static ssize_t show_blue(struct device *dev, struct device_attribute *attr,
 248                         char *buf)
 249{
 250        return show_color_common(dev, buf, BLUE);
 251}
 252
 253static ssize_t store_blue(struct device *dev, struct device_attribute *attr,
 254                          const char *buf, size_t count)
 255{
 256        int ret;
 257
 258        ret = store_color_common(dev, buf, BLUE);
 259        if (ret < 0)
 260                return ret;
 261        return count;
 262}
 263
 264static DEVICE_ATTR(blue, S_IRUGO | S_IWUSR, show_blue, store_blue);
 265
 266static ssize_t show_test(struct device *dev, struct device_attribute *attr,
 267                         char *buf)
 268{
 269        return scnprintf(buf, PAGE_SIZE,
 270                         "#Write into test to start test sequence!#\n");
 271}
 272
 273static ssize_t store_test(struct device *dev, struct device_attribute *attr,
 274                          const char *buf, size_t count)
 275{
 276
 277        struct i2c_client *client;
 278        int ret;
 279        client = to_i2c_client(dev);
 280
 281        /*test */
 282        ret = blinkm_test_run(client);
 283        if (ret < 0)
 284                return ret;
 285
 286        return count;
 287}
 288
 289static DEVICE_ATTR(test, S_IRUGO | S_IWUSR, show_test, store_test);
 290
 291/* TODO: HSB, fade, timeadj, script ... */
 292
 293static struct attribute *blinkm_attrs[] = {
 294        &dev_attr_red.attr,
 295        &dev_attr_green.attr,
 296        &dev_attr_blue.attr,
 297        &dev_attr_test.attr,
 298        NULL,
 299};
 300
 301static const struct attribute_group blinkm_group = {
 302        .name = "blinkm",
 303        .attrs = blinkm_attrs,
 304};
 305
 306static int blinkm_write(struct i2c_client *client, int cmd, u8 *arg)
 307{
 308        int result;
 309        int i;
 310        int arglen = blinkm_cmds[cmd].nr_args;
 311        /* write out cmd to blinkm - always / default step */
 312        result = i2c_smbus_write_byte(client, blinkm_cmds[cmd].cmdbyte);
 313        if (result < 0)
 314                return result;
 315        /* no args to write out */
 316        if (arglen == 0)
 317                return 0;
 318
 319        for (i = 0; i < arglen; i++) {
 320                /* repeat for arglen */
 321                result = i2c_smbus_write_byte(client, arg[i]);
 322                if (result < 0)
 323                        return result;
 324        }
 325        return 0;
 326}
 327
 328static int blinkm_read(struct i2c_client *client, int cmd, u8 *arg)
 329{
 330        int result;
 331        int i;
 332        int retlen = blinkm_cmds[cmd].nr_ret;
 333        for (i = 0; i < retlen; i++) {
 334                /* repeat for retlen */
 335                result = i2c_smbus_read_byte(client);
 336                if (result < 0)
 337                        return result;
 338                arg[i] = result;
 339        }
 340
 341        return 0;
 342}
 343
 344static int blinkm_transfer_hw(struct i2c_client *client, int cmd)
 345{
 346        /* the protocol is simple but non-standard:
 347         * e.g.  cmd 'g' (= 0x67) for "get device address"
 348         * - which defaults to 0x09 - would be the sequence:
 349         *   a) write 0x67 to the device (byte write)
 350         *   b) read the value (0x09) back right after (byte read)
 351         *
 352         * Watch out for "unfinished" sequences (i.e. not enough reads
 353         * or writes after a command. It will make the blinkM misbehave.
 354         * Sequence is key here.
 355         */
 356
 357        /* args / return are in private data struct */
 358        struct blinkm_data *data = i2c_get_clientdata(client);
 359
 360        /* We start hardware transfers which are not to be
 361         * mixed with other commands. Aquire a lock now. */
 362        if (mutex_lock_interruptible(&data->update_lock) < 0)
 363                return -EAGAIN;
 364
 365        /* switch cmd - usually write before reads */
 366        switch (cmd) {
 367        case BLM_FADE_RAND_RGB:
 368        case BLM_GO_RGB:
 369        case BLM_FADE_RGB:
 370                data->args[0] = data->next_red;
 371                data->args[1] = data->next_green;
 372                data->args[2] = data->next_blue;
 373                blinkm_write(client, cmd, data->args);
 374                data->red = data->args[0];
 375                data->green = data->args[1];
 376                data->blue = data->args[2];
 377                break;
 378        case BLM_FADE_HSB:
 379        case BLM_FADE_RAND_HSB:
 380                data->args[0] = data->next_hue;
 381                data->args[1] = data->next_saturation;
 382                data->args[2] = data->next_brightness;
 383                blinkm_write(client, cmd, data->args);
 384                data->hue = data->next_hue;
 385                data->saturation = data->next_saturation;
 386                data->brightness = data->next_brightness;
 387                break;
 388        case BLM_PLAY_SCRIPT:
 389                data->args[0] = data->script_id;
 390                data->args[1] = data->script_repeats;
 391                data->args[2] = data->script_startline;
 392                blinkm_write(client, cmd, data->args);
 393                break;
 394        case BLM_STOP_SCRIPT:
 395                blinkm_write(client, cmd, NULL);
 396                break;
 397        case BLM_GET_CUR_RGB:
 398                data->args[0] = data->red;
 399                data->args[1] = data->green;
 400                data->args[2] = data->blue;
 401                blinkm_write(client, cmd, NULL);
 402                blinkm_read(client, cmd, data->args);
 403                data->red = data->args[0];
 404                data->green = data->args[1];
 405                data->blue = data->args[2];
 406                break;
 407        case BLM_GET_ADDR:
 408                data->args[0] = data->i2c_addr;
 409                blinkm_write(client, cmd, NULL);
 410                blinkm_read(client, cmd, data->args);
 411                data->i2c_addr = data->args[0];
 412                break;
 413        case BLM_SET_TIME_ADJ:
 414        case BLM_SET_FADE_SPEED:
 415        case BLM_READ_SCRIPT_LINE:
 416        case BLM_WRITE_SCRIPT_LINE:
 417        case BLM_SET_SCRIPT_LR:
 418        case BLM_SET_ADDR:
 419        case BLM_GET_FW_VER:
 420        case BLM_SET_STARTUP_PARAM:
 421                dev_err(&client->dev,
 422                                "BlinkM: cmd %d not implemented yet.\n", cmd);
 423                break;
 424        default:
 425                dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd);
 426                mutex_unlock(&data->update_lock);
 427                return -EINVAL;
 428        }                       /* end switch(cmd) */
 429
 430        /* transfers done, unlock */
 431        mutex_unlock(&data->update_lock);
 432        return 0;
 433}
 434
 435static int blinkm_led_common_set(struct led_classdev *led_cdev,
 436                                 enum led_brightness value, int color)
 437{
 438        /* led_brightness is 0, 127 or 255 - we just use it here as-is */
 439        struct blinkm_led *led = cdev_to_blmled(led_cdev);
 440        struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
 441
 442        switch (color) {
 443        case RED:
 444                /* bail out if there's no change */
 445                if (data->next_red == (u8) value)
 446                        return 0;
 447                data->next_red = (u8) value;
 448                break;
 449        case GREEN:
 450                /* bail out if there's no change */
 451                if (data->next_green == (u8) value)
 452                        return 0;
 453                data->next_green = (u8) value;
 454                break;
 455        case BLUE:
 456                /* bail out if there's no change */
 457                if (data->next_blue == (u8) value)
 458                        return 0;
 459                data->next_blue = (u8) value;
 460                break;
 461
 462        default:
 463                dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n");
 464                return -EINVAL;
 465        }
 466
 467        blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
 468        dev_dbg(&led->i2c_client->dev,
 469                        "# DONE # next_red = %d, next_green = %d,"
 470                        " next_blue = %d\n",
 471                        data->next_red, data->next_green,
 472                        data->next_blue);
 473        return 0;
 474}
 475
 476static int blinkm_led_red_set(struct led_classdev *led_cdev,
 477                               enum led_brightness value)
 478{
 479        return blinkm_led_common_set(led_cdev, value, RED);
 480}
 481
 482static int blinkm_led_green_set(struct led_classdev *led_cdev,
 483                                 enum led_brightness value)
 484{
 485        return blinkm_led_common_set(led_cdev, value, GREEN);
 486}
 487
 488static int blinkm_led_blue_set(struct led_classdev *led_cdev,
 489                                enum led_brightness value)
 490{
 491        return blinkm_led_common_set(led_cdev, value, BLUE);
 492}
 493
 494static void blinkm_init_hw(struct i2c_client *client)
 495{
 496        int ret;
 497        ret = blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
 498        ret = blinkm_transfer_hw(client, BLM_GO_RGB);
 499}
 500
 501static int blinkm_test_run(struct i2c_client *client)
 502{
 503        int ret;
 504        struct blinkm_data *data = i2c_get_clientdata(client);
 505
 506        data->next_red = 0x01;
 507        data->next_green = 0x05;
 508        data->next_blue = 0x10;
 509        ret = blinkm_transfer_hw(client, BLM_GO_RGB);
 510        if (ret < 0)
 511                return ret;
 512        msleep(2000);
 513
 514        data->next_red = 0x25;
 515        data->next_green = 0x10;
 516        data->next_blue = 0x31;
 517        ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
 518        if (ret < 0)
 519                return ret;
 520        msleep(2000);
 521
 522        data->next_hue = 0x50;
 523        data->next_saturation = 0x10;
 524        data->next_brightness = 0x20;
 525        ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
 526        if (ret < 0)
 527                return ret;
 528        msleep(2000);
 529
 530        return 0;
 531}
 532
 533/* Return 0 if detection is successful, -ENODEV otherwise */
 534static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
 535{
 536        struct i2c_adapter *adapter = client->adapter;
 537        int ret;
 538        int count = 99;
 539        u8 tmpargs[7];
 540
 541        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
 542                                     | I2C_FUNC_SMBUS_WORD_DATA
 543                                     | I2C_FUNC_SMBUS_WRITE_BYTE))
 544                return -ENODEV;
 545
 546        /* Now, we do the remaining detection. Simple for now. */
 547        /* We might need more guards to protect other i2c slaves */
 548
 549        /* make sure the blinkM is balanced (read/writes) */
 550        while (count > 0) {
 551                ret = blinkm_write(client, BLM_GET_ADDR, NULL);
 552                usleep_range(5000, 10000);
 553                ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
 554                usleep_range(5000, 10000);
 555                if (tmpargs[0] == 0x09)
 556                        count = 0;
 557                count--;
 558        }
 559
 560        /* Step 1: Read BlinkM address back  -  cmd_char 'a' */
 561        ret = blinkm_write(client, BLM_GET_ADDR, NULL);
 562        if (ret < 0)
 563                return ret;
 564        usleep_range(20000, 30000);     /* allow a small delay */
 565        ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
 566        if (ret < 0)
 567                return ret;
 568
 569        if (tmpargs[0] != 0x09) {
 570                dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]);
 571                return -ENODEV;
 572        }
 573
 574        strlcpy(info->type, "blinkm", I2C_NAME_SIZE);
 575        return 0;
 576}
 577
 578static int blinkm_probe(struct i2c_client *client,
 579                        const struct i2c_device_id *id)
 580{
 581        struct blinkm_data *data;
 582        struct blinkm_led *led[3];
 583        int err, i;
 584        char blinkm_led_name[28];
 585
 586        data = devm_kzalloc(&client->dev,
 587                        sizeof(struct blinkm_data), GFP_KERNEL);
 588        if (!data) {
 589                err = -ENOMEM;
 590                goto exit;
 591        }
 592
 593        data->i2c_addr = 0x09;
 594        data->i2c_addr = 0x08;
 595        /* i2c addr  - use fake addr of 0x08 initially (real is 0x09) */
 596        data->fw_ver = 0xfe;
 597        /* firmware version - use fake until we read real value
 598         * (currently broken - BlinkM confused!) */
 599        data->script_id = 0x01;
 600        data->i2c_client = client;
 601
 602        i2c_set_clientdata(client, data);
 603        mutex_init(&data->update_lock);
 604
 605        /* Register sysfs hooks */
 606        err = sysfs_create_group(&client->dev.kobj, &blinkm_group);
 607        if (err < 0) {
 608                dev_err(&client->dev, "couldn't register sysfs group\n");
 609                goto exit;
 610        }
 611
 612        for (i = 0; i < 3; i++) {
 613                /* RED = 0, GREEN = 1, BLUE = 2 */
 614                led[i] = &data->blinkm_leds[i];
 615                led[i]->i2c_client = client;
 616                led[i]->id = i;
 617                led[i]->led_cdev.max_brightness = 255;
 618                led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME;
 619                switch (i) {
 620                case RED:
 621                        snprintf(blinkm_led_name, sizeof(blinkm_led_name),
 622                                         "blinkm-%d-%d-red",
 623                                         client->adapter->nr,
 624                                         client->addr);
 625                        led[i]->led_cdev.name = blinkm_led_name;
 626                        led[i]->led_cdev.brightness_set_blocking =
 627                                                        blinkm_led_red_set;
 628                        err = led_classdev_register(&client->dev,
 629                                                    &led[i]->led_cdev);
 630                        if (err < 0) {
 631                                dev_err(&client->dev,
 632                                        "couldn't register LED %s\n",
 633                                        led[i]->led_cdev.name);
 634                                goto failred;
 635                        }
 636                        break;
 637                case GREEN:
 638                        snprintf(blinkm_led_name, sizeof(blinkm_led_name),
 639                                         "blinkm-%d-%d-green",
 640                                         client->adapter->nr,
 641                                         client->addr);
 642                        led[i]->led_cdev.name = blinkm_led_name;
 643                        led[i]->led_cdev.brightness_set_blocking =
 644                                                        blinkm_led_green_set;
 645                        err = led_classdev_register(&client->dev,
 646                                                    &led[i]->led_cdev);
 647                        if (err < 0) {
 648                                dev_err(&client->dev,
 649                                        "couldn't register LED %s\n",
 650                                        led[i]->led_cdev.name);
 651                                goto failgreen;
 652                        }
 653                        break;
 654                case BLUE:
 655                        snprintf(blinkm_led_name, sizeof(blinkm_led_name),
 656                                         "blinkm-%d-%d-blue",
 657                                         client->adapter->nr,
 658                                         client->addr);
 659                        led[i]->led_cdev.name = blinkm_led_name;
 660                        led[i]->led_cdev.brightness_set_blocking =
 661                                                        blinkm_led_blue_set;
 662                        err = led_classdev_register(&client->dev,
 663                                                    &led[i]->led_cdev);
 664                        if (err < 0) {
 665                                dev_err(&client->dev,
 666                                        "couldn't register LED %s\n",
 667                                        led[i]->led_cdev.name);
 668                                goto failblue;
 669                        }
 670                        break;
 671                }               /* end switch */
 672        }                       /* end for */
 673
 674        /* Initialize the blinkm */
 675        blinkm_init_hw(client);
 676
 677        return 0;
 678
 679failblue:
 680        led_classdev_unregister(&led[GREEN]->led_cdev);
 681
 682failgreen:
 683        led_classdev_unregister(&led[RED]->led_cdev);
 684
 685failred:
 686        sysfs_remove_group(&client->dev.kobj, &blinkm_group);
 687exit:
 688        return err;
 689}
 690
 691static int blinkm_remove(struct i2c_client *client)
 692{
 693        struct blinkm_data *data = i2c_get_clientdata(client);
 694        int ret = 0;
 695        int i;
 696
 697        /* make sure no workqueue entries are pending */
 698        for (i = 0; i < 3; i++)
 699                led_classdev_unregister(&data->blinkm_leds[i].led_cdev);
 700
 701        /* reset rgb */
 702        data->next_red = 0x00;
 703        data->next_green = 0x00;
 704        data->next_blue = 0x00;
 705        ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
 706        if (ret < 0)
 707                dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
 708
 709        /* reset hsb */
 710        data->next_hue = 0x00;
 711        data->next_saturation = 0x00;
 712        data->next_brightness = 0x00;
 713        ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
 714        if (ret < 0)
 715                dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
 716
 717        /* red fade to off */
 718        data->next_red = 0xff;
 719        ret = blinkm_transfer_hw(client, BLM_GO_RGB);
 720        if (ret < 0)
 721                dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
 722
 723        /* off */
 724        data->next_red = 0x00;
 725        ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
 726        if (ret < 0)
 727                dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
 728
 729        sysfs_remove_group(&client->dev.kobj, &blinkm_group);
 730        return 0;
 731}
 732
 733static const struct i2c_device_id blinkm_id[] = {
 734        {"blinkm", 0},
 735        {}
 736};
 737
 738MODULE_DEVICE_TABLE(i2c, blinkm_id);
 739
 740  /* This is the driver that will be inserted */
 741static struct i2c_driver blinkm_driver = {
 742        .class = I2C_CLASS_HWMON,
 743        .driver = {
 744                   .name = "blinkm",
 745                   },
 746        .probe = blinkm_probe,
 747        .remove = blinkm_remove,
 748        .id_table = blinkm_id,
 749        .detect = blinkm_detect,
 750        .address_list = normal_i2c,
 751};
 752
 753module_i2c_driver(blinkm_driver);
 754
 755MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>");
 756MODULE_DESCRIPTION("BlinkM RGB LED driver");
 757MODULE_LICENSE("GPL");
 758
 759