]> Git Repo - linux.git/blob - drivers/leds/leds-blinkm.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / leds / leds-blinkm.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  leds-blinkm.c
4  *  (c) Jan-Simon Möller ([email protected])
5  *  (c) Joseph Strauss ([email protected])
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. Aquire a lock now. */
360         if (mutex_lock_interruptible(&data->update_lock) < 0)
361                 return -EAGAIN;
362
363         /* switch cmd - usually write before reads */
364         switch (cmd) {
365         case BLM_FADE_RAND_RGB:
366         case BLM_GO_RGB:
367         case BLM_FADE_RGB:
368                 data->args[0] = data->next_red;
369                 data->args[1] = data->next_green;
370                 data->args[2] = data->next_blue;
371                 blinkm_write(client, cmd, data->args);
372                 data->red = data->args[0];
373                 data->green = data->args[1];
374                 data->blue = data->args[2];
375                 break;
376         case BLM_FADE_HSB:
377         case BLM_FADE_RAND_HSB:
378                 data->args[0] = data->next_hue;
379                 data->args[1] = data->next_saturation;
380                 data->args[2] = data->next_brightness;
381                 blinkm_write(client, cmd, data->args);
382                 data->hue = data->next_hue;
383                 data->saturation = data->next_saturation;
384                 data->brightness = data->next_brightness;
385                 break;
386         case BLM_PLAY_SCRIPT:
387                 data->args[0] = data->script_id;
388                 data->args[1] = data->script_repeats;
389                 data->args[2] = data->script_startline;
390                 blinkm_write(client, cmd, data->args);
391                 break;
392         case BLM_STOP_SCRIPT:
393                 blinkm_write(client, cmd, NULL);
394                 break;
395         case BLM_GET_CUR_RGB:
396                 data->args[0] = data->red;
397                 data->args[1] = data->green;
398                 data->args[2] = data->blue;
399                 blinkm_write(client, cmd, NULL);
400                 blinkm_read(client, cmd, data->args);
401                 data->red = data->args[0];
402                 data->green = data->args[1];
403                 data->blue = data->args[2];
404                 break;
405         case BLM_GET_ADDR:
406                 data->args[0] = data->i2c_addr;
407                 blinkm_write(client, cmd, NULL);
408                 blinkm_read(client, cmd, data->args);
409                 data->i2c_addr = data->args[0];
410                 break;
411         case BLM_SET_TIME_ADJ:
412         case BLM_SET_FADE_SPEED:
413         case BLM_READ_SCRIPT_LINE:
414         case BLM_WRITE_SCRIPT_LINE:
415         case BLM_SET_SCRIPT_LR:
416         case BLM_SET_ADDR:
417         case BLM_GET_FW_VER:
418         case BLM_SET_STARTUP_PARAM:
419                 dev_err(&client->dev,
420                                 "BlinkM: cmd %d not implemented yet.\n", cmd);
421                 break;
422         default:
423                 dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd);
424                 mutex_unlock(&data->update_lock);
425                 return -EINVAL;
426         }                       /* end switch(cmd) */
427
428         /* transfers done, unlock */
429         mutex_unlock(&data->update_lock);
430         return 0;
431 }
432
433 static int blinkm_set_mc_brightness(struct led_classdev *led_cdev,
434                                  enum led_brightness value)
435 {
436         struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
437         struct blinkm_led *led = mcled_cdev_to_led(mcled_cdev);
438         struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
439
440         led_mc_calc_color_components(mcled_cdev, value);
441
442         data->next_red = (u8) mcled_cdev->subled_info[RED].brightness;
443         data->next_green = (u8) mcled_cdev->subled_info[GREEN].brightness;
444         data->next_blue = (u8) mcled_cdev->subled_info[BLUE].brightness;
445
446         blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
447
448         return 0;
449 }
450
451 static int blinkm_led_common_set(struct led_classdev *led_cdev,
452                                  enum led_brightness value, int color)
453 {
454         /* led_brightness is 0, 127 or 255 - we just use it here as-is */
455         struct blinkm_led *led = led_cdev_to_blmled(led_cdev);
456         struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
457
458         switch (color) {
459         case RED:
460                 /* bail out if there's no change */
461                 if (data->next_red == (u8) value)
462                         return 0;
463                 data->next_red = (u8) value;
464                 break;
465         case GREEN:
466                 /* bail out if there's no change */
467                 if (data->next_green == (u8) value)
468                         return 0;
469                 data->next_green = (u8) value;
470                 break;
471         case BLUE:
472                 /* bail out if there's no change */
473                 if (data->next_blue == (u8) value)
474                         return 0;
475                 data->next_blue = (u8) value;
476                 break;
477
478         default:
479                 dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n");
480                 return -EINVAL;
481         }
482
483         blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
484         dev_dbg(&led->i2c_client->dev,
485                         "# DONE # next_red = %d, next_green = %d,"
486                         " next_blue = %d\n",
487                         data->next_red, data->next_green,
488                         data->next_blue);
489         return 0;
490 }
491
492 static int blinkm_led_red_set(struct led_classdev *led_cdev,
493                                enum led_brightness value)
494 {
495         return blinkm_led_common_set(led_cdev, value, RED);
496 }
497
498 static int blinkm_led_green_set(struct led_classdev *led_cdev,
499                                  enum led_brightness value)
500 {
501         return blinkm_led_common_set(led_cdev, value, GREEN);
502 }
503
504 static int blinkm_led_blue_set(struct led_classdev *led_cdev,
505                                 enum led_brightness value)
506 {
507         return blinkm_led_common_set(led_cdev, value, BLUE);
508 }
509
510 static void blinkm_init_hw(struct i2c_client *client)
511 {
512         blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
513         blinkm_transfer_hw(client, BLM_GO_RGB);
514 }
515
516 static int blinkm_test_run(struct i2c_client *client)
517 {
518         int ret;
519         struct blinkm_data *data = i2c_get_clientdata(client);
520
521         data->next_red = 0x01;
522         data->next_green = 0x05;
523         data->next_blue = 0x10;
524         ret = blinkm_transfer_hw(client, BLM_GO_RGB);
525         if (ret < 0)
526                 return ret;
527         msleep(2000);
528
529         data->next_red = 0x25;
530         data->next_green = 0x10;
531         data->next_blue = 0x31;
532         ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
533         if (ret < 0)
534                 return ret;
535         msleep(2000);
536
537         data->next_hue = 0x50;
538         data->next_saturation = 0x10;
539         data->next_brightness = 0x20;
540         ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
541         if (ret < 0)
542                 return ret;
543         msleep(2000);
544
545         return 0;
546 }
547
548 /* Return 0 if detection is successful, -ENODEV otherwise */
549 static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
550 {
551         struct i2c_adapter *adapter = client->adapter;
552         int ret;
553         int count = 99;
554         u8 tmpargs[7];
555
556         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
557                                      | I2C_FUNC_SMBUS_WORD_DATA
558                                      | I2C_FUNC_SMBUS_WRITE_BYTE))
559                 return -ENODEV;
560
561         /* Now, we do the remaining detection. Simple for now. */
562         /* We might need more guards to protect other i2c slaves */
563
564         /* make sure the blinkM is balanced (read/writes) */
565         while (count > 0) {
566                 ret = blinkm_write(client, BLM_GET_ADDR, NULL);
567                 if (ret)
568                         return ret;
569                 usleep_range(5000, 10000);
570                 ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
571                 if (ret)
572                         return ret;
573                 usleep_range(5000, 10000);
574                 if (tmpargs[0] == 0x09)
575                         count = 0;
576                 count--;
577         }
578
579         /* Step 1: Read BlinkM address back  -  cmd_char 'a' */
580         ret = blinkm_write(client, BLM_GET_ADDR, NULL);
581         if (ret < 0)
582                 return ret;
583         usleep_range(20000, 30000);     /* allow a small delay */
584         ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
585         if (ret < 0)
586                 return ret;
587
588         if (tmpargs[0] != 0x09) {
589                 dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]);
590                 return -ENODEV;
591         }
592
593         strscpy(info->type, "blinkm", I2C_NAME_SIZE);
594         return 0;
595 }
596
597 static int register_separate_colors(struct i2c_client *client, struct blinkm_data *data)
598 {
599         /* 3 separate classes for red, green, and blue respectively */
600         struct blinkm_led *leds[NUM_LEDS];
601         int err;
602         char blinkm_led_name[28];
603         /* Register red, green, and blue sysfs classes */
604         for (int i = 0; i < NUM_LEDS; i++) {
605                 /* RED = 0, GREEN = 1, BLUE = 2 */
606                 leds[i] = &data->blinkm_leds[i];
607                 leds[i]->i2c_client = client;
608                 leds[i]->id = i;
609                 leds[i]->cdev.led_cdev.max_brightness = 255;
610                 leds[i]->cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME;
611                 switch (i) {
612                 case RED:
613                         scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
614                                          "blinkm-%d-%d-red",
615                                          client->adapter->nr,
616                                          client->addr);
617                         leds[i]->cdev.led_cdev.name = blinkm_led_name;
618                         leds[i]->cdev.led_cdev.brightness_set_blocking =
619                                                         blinkm_led_red_set;
620                         err = led_classdev_register(&client->dev,
621                                                         &leds[i]->cdev.led_cdev);
622                         if (err < 0) {
623                                 dev_err(&client->dev,
624                                         "couldn't register LED %s\n",
625                                         leds[i]->cdev.led_cdev.name);
626                                 goto failred;
627                         }
628                         break;
629                 case GREEN:
630                         scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
631                                          "blinkm-%d-%d-green",
632                                          client->adapter->nr,
633                                          client->addr);
634                         leds[i]->cdev.led_cdev.name = blinkm_led_name;
635                         leds[i]->cdev.led_cdev.brightness_set_blocking =
636                                                         blinkm_led_green_set;
637                         err = led_classdev_register(&client->dev,
638                                                 &leds[i]->cdev.led_cdev);
639                         if (err < 0) {
640                                 dev_err(&client->dev,
641                                         "couldn't register LED %s\n",
642                                         leds[i]->cdev.led_cdev.name);
643                                 goto failgreen;
644                         }
645                         break;
646                 case BLUE:
647                         scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
648                                          "blinkm-%d-%d-blue",
649                                          client->adapter->nr,
650                                          client->addr);
651                         leds[i]->cdev.led_cdev.name = blinkm_led_name;
652                         leds[i]->cdev.led_cdev.brightness_set_blocking =
653                                                         blinkm_led_blue_set;
654                         err = led_classdev_register(&client->dev,
655                                                         &leds[i]->cdev.led_cdev);
656                         if (err < 0) {
657                                 dev_err(&client->dev,
658                                         "couldn't register LED %s\n",
659                                         leds[i]->cdev.led_cdev.name);
660                                 goto failblue;
661                         }
662                         break;
663                 default:
664                         break;
665                 }               /* end switch */
666         }                       /* end for */
667         return 0;
668
669 failblue:
670         led_classdev_unregister(&leds[GREEN]->cdev.led_cdev);
671 failgreen:
672         led_classdev_unregister(&leds[RED]->cdev.led_cdev);
673 failred:
674         sysfs_remove_group(&client->dev.kobj, &blinkm_group);
675
676         return err;
677 }
678
679 static int register_multicolor(struct i2c_client *client, struct blinkm_data *data)
680 {
681         struct blinkm_led *mc_led;
682         struct mc_subled *mc_led_info;
683         char blinkm_led_name[28];
684         int err;
685
686         /* Register multicolor sysfs class */
687         /* The first element of leds is used for multicolor facilities */
688         mc_led = &data->blinkm_leds[RED];
689         mc_led->i2c_client = client;
690
691         mc_led_info = devm_kcalloc(&client->dev, NUM_LEDS, sizeof(*mc_led_info),
692                                         GFP_KERNEL);
693         if (!mc_led_info)
694                 return -ENOMEM;
695
696         mc_led_info[RED].color_index = LED_COLOR_ID_RED;
697         mc_led_info[GREEN].color_index = LED_COLOR_ID_GREEN;
698         mc_led_info[BLUE].color_index = LED_COLOR_ID_BLUE;
699
700         mc_led->cdev.mcled_cdev.subled_info = mc_led_info;
701         mc_led->cdev.mcled_cdev.num_colors = NUM_LEDS;
702         mc_led->cdev.mcled_cdev.led_cdev.brightness = 255;
703         mc_led->cdev.mcled_cdev.led_cdev.max_brightness = 255;
704         mc_led->cdev.mcled_cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME;
705
706         scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
707                  "blinkm-%d-%d:rgb:indicator",
708                  client->adapter->nr,
709                  client->addr);
710         mc_led->cdev.mcled_cdev.led_cdev.name = blinkm_led_name;
711         mc_led->cdev.mcled_cdev.led_cdev.brightness_set_blocking = blinkm_set_mc_brightness;
712
713         err = led_classdev_multicolor_register(&client->dev, &mc_led->cdev.mcled_cdev);
714         if (err < 0) {
715                 dev_err(&client->dev, "couldn't register LED %s\n",
716                                 mc_led->cdev.led_cdev.name);
717                 sysfs_remove_group(&client->dev.kobj, &blinkm_group);
718         }
719         return 0;
720 }
721
722 static int blinkm_probe(struct i2c_client *client)
723 {
724         struct blinkm_data *data;
725         int err;
726
727         data = devm_kzalloc(&client->dev,
728                         sizeof(struct blinkm_data), GFP_KERNEL);
729         if (!data)
730                 return -ENOMEM;
731
732         data->i2c_addr = 0x08;
733         /* i2c addr  - use fake addr of 0x08 initially (real is 0x09) */
734         data->fw_ver = 0xfe;
735         /* firmware version - use fake until we read real value
736          * (currently broken - BlinkM confused!)
737          */
738         data->script_id = 0x01;
739         data->i2c_client = client;
740
741         i2c_set_clientdata(client, data);
742         mutex_init(&data->update_lock);
743
744         /* Register sysfs hooks */
745         err = sysfs_create_group(&client->dev.kobj, &blinkm_group);
746         if (err < 0) {
747                 dev_err(&client->dev, "couldn't register sysfs group\n");
748                 return err;
749         }
750
751         if (!IS_ENABLED(CONFIG_LEDS_BLINKM_MULTICOLOR)) {
752                 err = register_separate_colors(client, data);
753                 if (err < 0)
754                         return err;
755         } else {
756                 err = register_multicolor(client, data);
757                 if (err < 0)
758                         return err;
759         }
760
761         blinkm_init_hw(client);
762
763         return 0;
764 }
765
766 static void blinkm_remove(struct i2c_client *client)
767 {
768         struct blinkm_data *data = i2c_get_clientdata(client);
769         int ret = 0;
770         int i;
771
772         /* make sure no workqueue entries are pending */
773         for (i = 0; i < NUM_LEDS; i++)
774                 led_classdev_unregister(&data->blinkm_leds[i].cdev.led_cdev);
775
776         /* reset rgb */
777         data->next_red = 0x00;
778         data->next_green = 0x00;
779         data->next_blue = 0x00;
780         ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
781         if (ret < 0)
782                 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
783
784         /* reset hsb */
785         data->next_hue = 0x00;
786         data->next_saturation = 0x00;
787         data->next_brightness = 0x00;
788         ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
789         if (ret < 0)
790                 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
791
792         /* red fade to off */
793         data->next_red = 0xff;
794         ret = blinkm_transfer_hw(client, BLM_GO_RGB);
795         if (ret < 0)
796                 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
797
798         /* off */
799         data->next_red = 0x00;
800         ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
801         if (ret < 0)
802                 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
803
804         sysfs_remove_group(&client->dev.kobj, &blinkm_group);
805 }
806
807 static const struct i2c_device_id blinkm_id[] = {
808         { "blinkm" },
809         {}
810 };
811
812 MODULE_DEVICE_TABLE(i2c, blinkm_id);
813
814   /* This is the driver that will be inserted */
815 static struct i2c_driver blinkm_driver = {
816         .class = I2C_CLASS_HWMON,
817         .driver = {
818                    .name = "blinkm",
819                    },
820         .probe = blinkm_probe,
821         .remove = blinkm_remove,
822         .id_table = blinkm_id,
823         .detect = blinkm_detect,
824         .address_list = normal_i2c,
825 };
826
827 module_i2c_driver(blinkm_driver);
828
829 MODULE_AUTHOR("Jan-Simon Moeller <[email protected]>");
830 MODULE_AUTHOR("Joseph Strauss <[email protected]>");
831 MODULE_DESCRIPTION("BlinkM RGB LED driver");
832 MODULE_LICENSE("GPL");
833
This page took 0.08125 seconds and 4 git commands to generate.