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