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