leds-blinkm.c 19 KB

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