Merge tag 'libnvdimm-fixes-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / platform / chrome / cros_ec_lightbar.c
1 // SPDX-License-Identifier: GPL-2.0+
2 // Expose the Chromebook Pixel lightbar to userspace
3 //
4 // Copyright (C) 2014 Google, Inc.
5
6 #include <linux/ctype.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
9 #include <linux/fs.h>
10 #include <linux/kobject.h>
11 #include <linux/mfd/cros_ec.h>
12 #include <linux/mfd/cros_ec_commands.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/sched.h>
16 #include <linux/types.h>
17 #include <linux/uaccess.h>
18 #include <linux/slab.h>
19
20 #define DRV_NAME "cros-ec-lightbar"
21
22 /* Rate-limit the lightbar interface to prevent DoS. */
23 static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
24
25 /*
26  * Whether or not we have given userspace control of the lightbar.
27  * If this is true, we won't do anything during suspend/resume.
28  */
29 static bool userspace_control;
30
31 static ssize_t interval_msec_show(struct device *dev,
32                                   struct device_attribute *attr, char *buf)
33 {
34         unsigned long msec = lb_interval_jiffies * 1000 / HZ;
35
36         return scnprintf(buf, PAGE_SIZE, "%lu\n", msec);
37 }
38
39 static ssize_t interval_msec_store(struct device *dev,
40                                    struct device_attribute *attr,
41                                    const char *buf, size_t count)
42 {
43         unsigned long msec;
44
45         if (kstrtoul(buf, 0, &msec))
46                 return -EINVAL;
47
48         lb_interval_jiffies = msec * HZ / 1000;
49
50         return count;
51 }
52
53 static DEFINE_MUTEX(lb_mutex);
54 /* Return 0 if able to throttle correctly, error otherwise */
55 static int lb_throttle(void)
56 {
57         static unsigned long last_access;
58         unsigned long now, next_timeslot;
59         long delay;
60         int ret = 0;
61
62         mutex_lock(&lb_mutex);
63
64         now = jiffies;
65         next_timeslot = last_access + lb_interval_jiffies;
66
67         if (time_before(now, next_timeslot)) {
68                 delay = (long)(next_timeslot) - (long)now;
69                 set_current_state(TASK_INTERRUPTIBLE);
70                 if (schedule_timeout(delay) > 0) {
71                         /* interrupted - just abort */
72                         ret = -EINTR;
73                         goto out;
74                 }
75                 now = jiffies;
76         }
77
78         last_access = now;
79 out:
80         mutex_unlock(&lb_mutex);
81
82         return ret;
83 }
84
85 static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec)
86 {
87         struct cros_ec_command *msg;
88         int len;
89
90         len = max(sizeof(struct ec_params_lightbar),
91                   sizeof(struct ec_response_lightbar));
92
93         msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
94         if (!msg)
95                 return NULL;
96
97         msg->version = 0;
98         msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset;
99         msg->outsize = sizeof(struct ec_params_lightbar);
100         msg->insize = sizeof(struct ec_response_lightbar);
101
102         return msg;
103 }
104
105 static int get_lightbar_version(struct cros_ec_dev *ec,
106                                 uint32_t *ver_ptr, uint32_t *flg_ptr)
107 {
108         struct ec_params_lightbar *param;
109         struct ec_response_lightbar *resp;
110         struct cros_ec_command *msg;
111         int ret;
112
113         msg = alloc_lightbar_cmd_msg(ec);
114         if (!msg)
115                 return 0;
116
117         param = (struct ec_params_lightbar *)msg->data;
118         param->cmd = LIGHTBAR_CMD_VERSION;
119         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
120         if (ret < 0) {
121                 ret = 0;
122                 goto exit;
123         }
124
125         switch (msg->result) {
126         case EC_RES_INVALID_PARAM:
127                 /* Pixel had no version command. */
128                 if (ver_ptr)
129                         *ver_ptr = 0;
130                 if (flg_ptr)
131                         *flg_ptr = 0;
132                 ret = 1;
133                 goto exit;
134
135         case EC_RES_SUCCESS:
136                 resp = (struct ec_response_lightbar *)msg->data;
137
138                 /* Future devices w/lightbars should implement this command */
139                 if (ver_ptr)
140                         *ver_ptr = resp->version.num;
141                 if (flg_ptr)
142                         *flg_ptr = resp->version.flags;
143                 ret = 1;
144                 goto exit;
145         }
146
147         /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */
148         ret = 0;
149 exit:
150         kfree(msg);
151         return ret;
152 }
153
154 static ssize_t version_show(struct device *dev,
155                             struct device_attribute *attr, char *buf)
156 {
157         uint32_t version = 0, flags = 0;
158         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
159         int ret;
160
161         ret = lb_throttle();
162         if (ret)
163                 return ret;
164
165         /* This should always succeed, because we check during init. */
166         if (!get_lightbar_version(ec, &version, &flags))
167                 return -EIO;
168
169         return scnprintf(buf, PAGE_SIZE, "%d %d\n", version, flags);
170 }
171
172 static ssize_t brightness_store(struct device *dev,
173                                 struct device_attribute *attr,
174                                 const char *buf, size_t count)
175 {
176         struct ec_params_lightbar *param;
177         struct cros_ec_command *msg;
178         int ret;
179         unsigned int val;
180         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
181
182         if (kstrtouint(buf, 0, &val))
183                 return -EINVAL;
184
185         msg = alloc_lightbar_cmd_msg(ec);
186         if (!msg)
187                 return -ENOMEM;
188
189         param = (struct ec_params_lightbar *)msg->data;
190         param->cmd = LIGHTBAR_CMD_SET_BRIGHTNESS;
191         param->set_brightness.num = val;
192         ret = lb_throttle();
193         if (ret)
194                 goto exit;
195
196         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
197         if (ret < 0)
198                 goto exit;
199
200         if (msg->result != EC_RES_SUCCESS) {
201                 ret = -EINVAL;
202                 goto exit;
203         }
204
205         ret = count;
206 exit:
207         kfree(msg);
208         return ret;
209 }
210
211
212 /*
213  * We expect numbers, and we'll keep reading until we find them, skipping over
214  * any whitespace (sysfs guarantees that the input is null-terminated). Every
215  * four numbers are sent to the lightbar as <LED,R,G,B>. We fail at the first
216  * parsing error, if we don't parse any numbers, or if we have numbers left
217  * over.
218  */
219 static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
220                              const char *buf, size_t count)
221 {
222         struct ec_params_lightbar *param;
223         struct cros_ec_command *msg;
224         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
225         unsigned int val[4];
226         int ret, i = 0, j = 0, ok = 0;
227
228         msg = alloc_lightbar_cmd_msg(ec);
229         if (!msg)
230                 return -ENOMEM;
231
232         do {
233                 /* Skip any whitespace */
234                 while (*buf && isspace(*buf))
235                         buf++;
236
237                 if (!*buf)
238                         break;
239
240                 ret = sscanf(buf, "%i", &val[i++]);
241                 if (ret == 0)
242                         goto exit;
243
244                 if (i == 4) {
245                         param = (struct ec_params_lightbar *)msg->data;
246                         param->cmd = LIGHTBAR_CMD_SET_RGB;
247                         param->set_rgb.led = val[0];
248                         param->set_rgb.red = val[1];
249                         param->set_rgb.green = val[2];
250                         param->set_rgb.blue = val[3];
251                         /*
252                          * Throttle only the first of every four transactions,
253                          * so that the user can update all four LEDs at once.
254                          */
255                         if ((j++ % 4) == 0) {
256                                 ret = lb_throttle();
257                                 if (ret)
258                                         goto exit;
259                         }
260
261                         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
262                         if (ret < 0)
263                                 goto exit;
264
265                         if (msg->result != EC_RES_SUCCESS)
266                                 goto exit;
267
268                         i = 0;
269                         ok = 1;
270                 }
271
272                 /* Skip over the number we just read */
273                 while (*buf && !isspace(*buf))
274                         buf++;
275
276         } while (*buf);
277
278 exit:
279         kfree(msg);
280         return (ok && i == 0) ? count : -EINVAL;
281 }
282
283 static char const *seqname[] = {
284         "ERROR", "S5", "S3", "S0", "S5S3", "S3S0",
285         "S0S3", "S3S5", "STOP", "RUN", "KONAMI",
286         "TAP", "PROGRAM",
287 };
288
289 static ssize_t sequence_show(struct device *dev,
290                              struct device_attribute *attr, char *buf)
291 {
292         struct ec_params_lightbar *param;
293         struct ec_response_lightbar *resp;
294         struct cros_ec_command *msg;
295         int ret;
296         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
297
298         msg = alloc_lightbar_cmd_msg(ec);
299         if (!msg)
300                 return -ENOMEM;
301
302         param = (struct ec_params_lightbar *)msg->data;
303         param->cmd = LIGHTBAR_CMD_GET_SEQ;
304         ret = lb_throttle();
305         if (ret)
306                 goto exit;
307
308         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
309         if (ret < 0)
310                 goto exit;
311
312         if (msg->result != EC_RES_SUCCESS) {
313                 ret = scnprintf(buf, PAGE_SIZE,
314                                 "ERROR: EC returned %d\n", msg->result);
315                 goto exit;
316         }
317
318         resp = (struct ec_response_lightbar *)msg->data;
319         if (resp->get_seq.num >= ARRAY_SIZE(seqname))
320                 ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num);
321         else
322                 ret = scnprintf(buf, PAGE_SIZE, "%s\n",
323                                 seqname[resp->get_seq.num]);
324
325 exit:
326         kfree(msg);
327         return ret;
328 }
329
330 static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
331 {
332         struct ec_params_lightbar *param;
333         struct cros_ec_command *msg;
334         int ret;
335
336         msg = alloc_lightbar_cmd_msg(ec);
337         if (!msg)
338                 return -ENOMEM;
339
340         param = (struct ec_params_lightbar *)msg->data;
341         param->cmd = cmd;
342
343         ret = lb_throttle();
344         if (ret)
345                 goto error;
346
347         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
348         if (ret < 0)
349                 goto error;
350         if (msg->result != EC_RES_SUCCESS) {
351                 ret = -EINVAL;
352                 goto error;
353         }
354         ret = 0;
355 error:
356         kfree(msg);
357
358         return ret;
359 }
360
361 static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
362 {
363         struct ec_params_lightbar *param;
364         struct cros_ec_command *msg;
365         int ret;
366
367         msg = alloc_lightbar_cmd_msg(ec);
368         if (!msg)
369                 return -ENOMEM;
370
371         param = (struct ec_params_lightbar *)msg->data;
372
373         param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL;
374         param->manual_suspend_ctrl.enable = enable;
375
376         ret = lb_throttle();
377         if (ret)
378                 goto error;
379
380         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
381         if (ret < 0)
382                 goto error;
383         if (msg->result != EC_RES_SUCCESS) {
384                 ret = -EINVAL;
385                 goto error;
386         }
387         ret = 0;
388 error:
389         kfree(msg);
390
391         return ret;
392 }
393
394 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
395                               const char *buf, size_t count)
396 {
397         struct ec_params_lightbar *param;
398         struct cros_ec_command *msg;
399         unsigned int num;
400         int ret, len;
401         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
402
403         for (len = 0; len < count; len++)
404                 if (!isalnum(buf[len]))
405                         break;
406
407         for (num = 0; num < ARRAY_SIZE(seqname); num++)
408                 if (!strncasecmp(seqname[num], buf, len))
409                         break;
410
411         if (num >= ARRAY_SIZE(seqname)) {
412                 ret = kstrtouint(buf, 0, &num);
413                 if (ret)
414                         return ret;
415         }
416
417         msg = alloc_lightbar_cmd_msg(ec);
418         if (!msg)
419                 return -ENOMEM;
420
421         param = (struct ec_params_lightbar *)msg->data;
422         param->cmd = LIGHTBAR_CMD_SEQ;
423         param->seq.num = num;
424         ret = lb_throttle();
425         if (ret)
426                 goto exit;
427
428         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
429         if (ret < 0)
430                 goto exit;
431
432         if (msg->result != EC_RES_SUCCESS) {
433                 ret = -EINVAL;
434                 goto exit;
435         }
436
437         ret = count;
438 exit:
439         kfree(msg);
440         return ret;
441 }
442
443 static ssize_t program_store(struct device *dev, struct device_attribute *attr,
444                              const char *buf, size_t count)
445 {
446         int extra_bytes, max_size, ret;
447         struct ec_params_lightbar *param;
448         struct cros_ec_command *msg;
449         struct cros_ec_dev *ec = to_cros_ec_dev(dev);
450
451         /*
452          * We might need to reject the program for size reasons. The EC
453          * enforces a maximum program size, but we also don't want to try
454          * and send a program that is too big for the protocol. In order
455          * to ensure the latter, we also need to ensure we have extra bytes
456          * to represent the rest of the packet.
457          */
458         extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
459         max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
460         if (count > max_size) {
461                 dev_err(dev, "Program is %u bytes, too long to send (max: %u)",
462                         (unsigned int)count, max_size);
463
464                 return -EINVAL;
465         }
466
467         msg = alloc_lightbar_cmd_msg(ec);
468         if (!msg)
469                 return -ENOMEM;
470
471         ret = lb_throttle();
472         if (ret)
473                 goto exit;
474
475         dev_info(dev, "Copying %zu byte program to EC", count);
476
477         param = (struct ec_params_lightbar *)msg->data;
478         param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
479
480         param->set_program.size = count;
481         memcpy(param->set_program.data, buf, count);
482
483         /*
484          * We need to set the message size manually or else it will use
485          * EC_LB_PROG_LEN. This might be too long, and the program
486          * is unlikely to use all of the space.
487          */
488         msg->outsize = count + extra_bytes;
489
490         ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
491         if (ret < 0)
492                 goto exit;
493         if (msg->result != EC_RES_SUCCESS) {
494                 ret = -EINVAL;
495                 goto exit;
496         }
497
498         ret = count;
499 exit:
500         kfree(msg);
501
502         return ret;
503 }
504
505 static ssize_t userspace_control_show(struct device *dev,
506                                       struct device_attribute *attr,
507                                       char *buf)
508 {
509         return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control);
510 }
511
512 static ssize_t userspace_control_store(struct device *dev,
513                                        struct device_attribute *attr,
514                                        const char *buf,
515                                        size_t count)
516 {
517         bool enable;
518         int ret;
519
520         ret = strtobool(buf, &enable);
521         if (ret < 0)
522                 return ret;
523
524         userspace_control = enable;
525
526         return count;
527 }
528
529 /* Module initialization */
530
531 static DEVICE_ATTR_RW(interval_msec);
532 static DEVICE_ATTR_RO(version);
533 static DEVICE_ATTR_WO(brightness);
534 static DEVICE_ATTR_WO(led_rgb);
535 static DEVICE_ATTR_RW(sequence);
536 static DEVICE_ATTR_WO(program);
537 static DEVICE_ATTR_RW(userspace_control);
538
539 static struct attribute *__lb_cmds_attrs[] = {
540         &dev_attr_interval_msec.attr,
541         &dev_attr_version.attr,
542         &dev_attr_brightness.attr,
543         &dev_attr_led_rgb.attr,
544         &dev_attr_sequence.attr,
545         &dev_attr_program.attr,
546         &dev_attr_userspace_control.attr,
547         NULL,
548 };
549
550 struct attribute_group cros_ec_lightbar_attr_group = {
551         .name = "lightbar",
552         .attrs = __lb_cmds_attrs,
553 };
554
555 static int cros_ec_lightbar_probe(struct platform_device *pd)
556 {
557         struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
558         struct cros_ec_platform *pdata = dev_get_platdata(ec_dev->dev);
559         struct device *dev = &pd->dev;
560         int ret;
561
562         /*
563          * Only instantiate the lightbar if the EC name is 'cros_ec'. Other EC
564          * devices like 'cros_pd' doesn't have a lightbar.
565          */
566         if (strcmp(pdata->ec_name, CROS_EC_DEV_NAME) != 0)
567                 return -ENODEV;
568
569         /*
570          * Ask then for the lightbar version, if it's 0 then the 'cros_ec'
571          * doesn't have a lightbar.
572          */
573         if (!get_lightbar_version(ec_dev, NULL, NULL))
574                 return -ENODEV;
575
576         /* Take control of the lightbar from the EC. */
577         lb_manual_suspend_ctrl(ec_dev, 1);
578
579         ret = sysfs_create_group(&ec_dev->class_dev.kobj,
580                                  &cros_ec_lightbar_attr_group);
581         if (ret < 0)
582                 dev_err(dev, "failed to create %s attributes. err=%d\n",
583                         cros_ec_lightbar_attr_group.name, ret);
584
585         return ret;
586 }
587
588 static int cros_ec_lightbar_remove(struct platform_device *pd)
589 {
590         struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
591
592         sysfs_remove_group(&ec_dev->class_dev.kobj,
593                            &cros_ec_lightbar_attr_group);
594
595         /* Let the EC take over the lightbar again. */
596         lb_manual_suspend_ctrl(ec_dev, 0);
597
598         return 0;
599 }
600
601 static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
602 {
603         struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
604
605         if (userspace_control)
606                 return 0;
607
608         return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_RESUME);
609 }
610
611 static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
612 {
613         struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
614
615         if (userspace_control)
616                 return 0;
617
618         return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_SUSPEND);
619 }
620
621 static SIMPLE_DEV_PM_OPS(cros_ec_lightbar_pm_ops,
622                          cros_ec_lightbar_suspend, cros_ec_lightbar_resume);
623
624 static struct platform_driver cros_ec_lightbar_driver = {
625         .driver = {
626                 .name = DRV_NAME,
627                 .pm = &cros_ec_lightbar_pm_ops,
628         },
629         .probe = cros_ec_lightbar_probe,
630         .remove = cros_ec_lightbar_remove,
631 };
632
633 module_platform_driver(cros_ec_lightbar_driver);
634
635 MODULE_LICENSE("GPL");
636 MODULE_DESCRIPTION("Expose the Chromebook Pixel's lightbar to userspace");
637 MODULE_ALIAS("platform:" DRV_NAME);