Merge tag 'tag-chrome-platform-for-v5.2' of ssh://gitolite.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / drivers / staging / greybus / vibrator.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Greybus Vibrator protocol driver.
4  *
5  * Copyright 2014 Google Inc.
6  * Copyright 2014 Linaro Ltd.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/device.h>
13 #include <linux/kdev_t.h>
14 #include <linux/idr.h>
15 #include <linux/pm_runtime.h>
16
17 #include "greybus.h"
18
19 struct gb_vibrator_device {
20         struct gb_connection    *connection;
21         struct device           *dev;
22         int                     minor;          /* vibrator minor number */
23         struct delayed_work     delayed_work;
24 };
25
26 /* Greybus Vibrator operation types */
27 #define GB_VIBRATOR_TYPE_ON                     0x02
28 #define GB_VIBRATOR_TYPE_OFF                    0x03
29
30 static int turn_off(struct gb_vibrator_device *vib)
31 {
32         struct gb_bundle *bundle = vib->connection->bundle;
33         int ret;
34
35         ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF,
36                                 NULL, 0, NULL, 0);
37
38         gb_pm_runtime_put_autosuspend(bundle);
39
40         return ret;
41 }
42
43 static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
44 {
45         struct gb_bundle *bundle = vib->connection->bundle;
46         int ret;
47
48         ret = gb_pm_runtime_get_sync(bundle);
49         if (ret)
50                 return ret;
51
52         /* Vibrator was switched ON earlier */
53         if (cancel_delayed_work_sync(&vib->delayed_work))
54                 turn_off(vib);
55
56         ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON,
57                                 NULL, 0, NULL, 0);
58         if (ret) {
59                 gb_pm_runtime_put_autosuspend(bundle);
60                 return ret;
61         }
62
63         schedule_delayed_work(&vib->delayed_work, msecs_to_jiffies(timeout_ms));
64
65         return 0;
66 }
67
68 static void gb_vibrator_worker(struct work_struct *work)
69 {
70         struct delayed_work *delayed_work = to_delayed_work(work);
71         struct gb_vibrator_device *vib =
72                 container_of(delayed_work,
73                              struct gb_vibrator_device,
74                              delayed_work);
75
76         turn_off(vib);
77 }
78
79 static ssize_t timeout_store(struct device *dev, struct device_attribute *attr,
80                              const char *buf, size_t count)
81 {
82         struct gb_vibrator_device *vib = dev_get_drvdata(dev);
83         unsigned long val;
84         int retval;
85
86         retval = kstrtoul(buf, 10, &val);
87         if (retval < 0) {
88                 dev_err(dev, "could not parse timeout value %d\n", retval);
89                 return retval;
90         }
91
92         if (val)
93                 retval = turn_on(vib, (u16)val);
94         else
95                 retval = turn_off(vib);
96         if (retval)
97                 return retval;
98
99         return count;
100 }
101 static DEVICE_ATTR_WO(timeout);
102
103 static struct attribute *vibrator_attrs[] = {
104         &dev_attr_timeout.attr,
105         NULL,
106 };
107 ATTRIBUTE_GROUPS(vibrator);
108
109 static struct class vibrator_class = {
110         .name           = "vibrator",
111         .owner          = THIS_MODULE,
112         .dev_groups     = vibrator_groups,
113 };
114
115 static DEFINE_IDA(minors);
116
117 static int gb_vibrator_probe(struct gb_bundle *bundle,
118                              const struct greybus_bundle_id *id)
119 {
120         struct greybus_descriptor_cport *cport_desc;
121         struct gb_connection *connection;
122         struct gb_vibrator_device *vib;
123         struct device *dev;
124         int retval;
125
126         if (bundle->num_cports != 1)
127                 return -ENODEV;
128
129         cport_desc = &bundle->cport_desc[0];
130         if (cport_desc->protocol_id != GREYBUS_PROTOCOL_VIBRATOR)
131                 return -ENODEV;
132
133         vib = kzalloc(sizeof(*vib), GFP_KERNEL);
134         if (!vib)
135                 return -ENOMEM;
136
137         connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
138                                           NULL);
139         if (IS_ERR(connection)) {
140                 retval = PTR_ERR(connection);
141                 goto err_free_vib;
142         }
143         gb_connection_set_data(connection, vib);
144
145         vib->connection = connection;
146
147         greybus_set_drvdata(bundle, vib);
148
149         retval = gb_connection_enable(connection);
150         if (retval)
151                 goto err_connection_destroy;
152
153         /*
154          * For now we create a device in sysfs for the vibrator, but odds are
155          * there is a "real" device somewhere in the kernel for this, but I
156          * can't find it at the moment...
157          */
158         vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
159         if (vib->minor < 0) {
160                 retval = vib->minor;
161                 goto err_connection_disable;
162         }
163         dev = device_create(&vibrator_class, &bundle->dev,
164                             MKDEV(0, 0), vib, "vibrator%d", vib->minor);
165         if (IS_ERR(dev)) {
166                 retval = -EINVAL;
167                 goto err_ida_remove;
168         }
169         vib->dev = dev;
170
171         INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker);
172
173         gb_pm_runtime_put_autosuspend(bundle);
174
175         return 0;
176
177 err_ida_remove:
178         ida_simple_remove(&minors, vib->minor);
179 err_connection_disable:
180         gb_connection_disable(connection);
181 err_connection_destroy:
182         gb_connection_destroy(connection);
183 err_free_vib:
184         kfree(vib);
185
186         return retval;
187 }
188
189 static void gb_vibrator_disconnect(struct gb_bundle *bundle)
190 {
191         struct gb_vibrator_device *vib = greybus_get_drvdata(bundle);
192         int ret;
193
194         ret = gb_pm_runtime_get_sync(bundle);
195         if (ret)
196                 gb_pm_runtime_get_noresume(bundle);
197
198         if (cancel_delayed_work_sync(&vib->delayed_work))
199                 turn_off(vib);
200
201         device_unregister(vib->dev);
202         ida_simple_remove(&minors, vib->minor);
203         gb_connection_disable(vib->connection);
204         gb_connection_destroy(vib->connection);
205         kfree(vib);
206 }
207
208 static const struct greybus_bundle_id gb_vibrator_id_table[] = {
209         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
210         { }
211 };
212 MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
213
214 static struct greybus_driver gb_vibrator_driver = {
215         .name           = "vibrator",
216         .probe          = gb_vibrator_probe,
217         .disconnect     = gb_vibrator_disconnect,
218         .id_table       = gb_vibrator_id_table,
219 };
220
221 static __init int gb_vibrator_init(void)
222 {
223         int retval;
224
225         retval = class_register(&vibrator_class);
226         if (retval)
227                 return retval;
228
229         retval = greybus_register(&gb_vibrator_driver);
230         if (retval)
231                 goto err_class_unregister;
232
233         return 0;
234
235 err_class_unregister:
236         class_unregister(&vibrator_class);
237
238         return retval;
239 }
240 module_init(gb_vibrator_init);
241
242 static __exit void gb_vibrator_exit(void)
243 {
244         greybus_deregister(&gb_vibrator_driver);
245         class_unregister(&vibrator_class);
246         ida_destroy(&minors);
247 }
248 module_exit(gb_vibrator_exit);
249
250 MODULE_LICENSE("GPL v2");