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