1
2
3
4
5
6
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
19struct gb_vibrator_device {
20 struct gb_connection *connection;
21 struct device *dev;
22 int minor;
23 struct delayed_work delayed_work;
24};
25
26
27#define GB_VIBRATOR_TYPE_ON 0x02
28#define GB_VIBRATOR_TYPE_OFF 0x03
29
30static 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
43static 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
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
68static 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
79static 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}
101static DEVICE_ATTR_WO(timeout);
102
103static struct attribute *vibrator_attrs[] = {
104 &dev_attr_timeout.attr,
105 NULL,
106};
107ATTRIBUTE_GROUPS(vibrator);
108
109static struct class vibrator_class = {
110 .name = "vibrator",
111 .owner = THIS_MODULE,
112 .dev_groups = vibrator_groups,
113};
114
115static DEFINE_IDA(minors);
116
117static 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
155
156
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
177err_ida_remove:
178 ida_simple_remove(&minors, vib->minor);
179err_connection_disable:
180 gb_connection_disable(connection);
181err_connection_destroy:
182 gb_connection_destroy(connection);
183err_free_vib:
184 kfree(vib);
185
186 return retval;
187}
188
189static 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
208static const struct greybus_bundle_id gb_vibrator_id_table[] = {
209 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
210 { }
211};
212MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
213
214static 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
221static __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
235err_class_unregister:
236 class_unregister(&vibrator_class);
237
238 return retval;
239}
240module_init(gb_vibrator_init);
241
242static __exit void gb_vibrator_exit(void)
243{
244 greybus_deregister(&gb_vibrator_driver);
245 class_unregister(&vibrator_class);
246 ida_destroy(&minors);
247}
248module_exit(gb_vibrator_exit);
249
250MODULE_LICENSE("GPL v2");
251