xref: /linux/drivers/staging/greybus/vibrator.c (revision e2be04c7f9958dde770eeb8b30e829ca969b37bb)
1 /*
2  * Greybus Vibrator protocol driver.
3  *
4  * Copyright 2014 Google Inc.
5  * Copyright 2014 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
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 
20 struct gb_vibrator_device {
21 	struct gb_connection	*connection;
22 	struct device		*dev;
23 	int			minor;		/* vibrator minor number */
24 	struct delayed_work     delayed_work;
25 };
26 
27 /* Greybus Vibrator operation types */
28 #define	GB_VIBRATOR_TYPE_ON			0x02
29 #define	GB_VIBRATOR_TYPE_OFF			0x03
30 
31 static 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 
44 static 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 	/* Vibrator was switched ON earlier */
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 
69 static 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 
80 static 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 }
102 static DEVICE_ATTR_WO(timeout);
103 
104 static struct attribute *vibrator_attrs[] = {
105 	&dev_attr_timeout.attr,
106 	NULL,
107 };
108 ATTRIBUTE_GROUPS(vibrator);
109 
110 static struct class vibrator_class = {
111 	.name		= "vibrator",
112 	.owner		= THIS_MODULE,
113 	.dev_groups	= vibrator_groups,
114 };
115 
116 static DEFINE_IDA(minors);
117 
118 static 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 	 * For now we create a device in sysfs for the vibrator, but odds are
156 	 * there is a "real" device somewhere in the kernel for this, but I
157 	 * can't find it at the moment...
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 
178 err_ida_remove:
179 	ida_simple_remove(&minors, vib->minor);
180 err_connection_disable:
181 	gb_connection_disable(connection);
182 err_connection_destroy:
183 	gb_connection_destroy(connection);
184 err_free_vib:
185 	kfree(vib);
186 
187 	return retval;
188 }
189 
190 static 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 
209 static const struct greybus_bundle_id gb_vibrator_id_table[] = {
210 	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
211 	{ }
212 };
213 MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
214 
215 static 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 
222 static __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 
236 err_class_unregister:
237 	class_unregister(&vibrator_class);
238 
239 	return retval;
240 }
241 module_init(gb_vibrator_init);
242 
243 static __exit void gb_vibrator_exit(void)
244 {
245 	greybus_deregister(&gb_vibrator_driver);
246 	class_unregister(&vibrator_class);
247 	ida_destroy(&minors);
248 }
249 module_exit(gb_vibrator_exit);
250 
251 MODULE_LICENSE("GPL v2");
252