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