root/drivers/leds/leds-blinkm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. show_color_common
  2. store_color_common
  3. show_red
  4. store_red
  5. show_green
  6. store_green
  7. show_blue
  8. store_blue
  9. show_test
  10. store_test
  11. blinkm_write
  12. blinkm_read
  13. blinkm_transfer_hw
  14. blinkm_led_common_set
  15. blinkm_led_red_set
  16. blinkm_led_green_set
  17. blinkm_led_blue_set
  18. blinkm_init_hw
  19. blinkm_test_run
  20. blinkm_detect
  21. blinkm_probe
  22. blinkm_remove

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

/* [<][>][^][v][top][bottom][index][help] */