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