leds-blinkm.c 18 KB

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