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
18struct 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
29static 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
42static 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
67static 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
78static 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}
100static DEVICE_ATTR_WO(timeout);
101
102static struct attribute *vibrator_attrs[] = {
103	&dev_attr_timeout.attr,
104	NULL,
105};
106ATTRIBUTE_GROUPS(vibrator);
107
108static struct class vibrator_class = {
109	.name		= "vibrator",
110	.dev_groups	= vibrator_groups,
111};
112
113static DEFINE_IDA(minors);
114
115static int gb_vibrator_probe(struct gb_bundle *bundle,
116			     const struct greybus_bundle_id *id)
117{
118	struct greybus_descriptor_cport *cport_desc;
119	struct gb_connection *connection;
120	struct gb_vibrator_device *vib;
121	struct device *dev;
122	int retval;
123
124	if (bundle->num_cports != 1)
125		return -ENODEV;
126
127	cport_desc = &bundle->cport_desc[0];
128	if (cport_desc->protocol_id != GREYBUS_PROTOCOL_VIBRATOR)
129		return -ENODEV;
130
131	vib = kzalloc(sizeof(*vib), GFP_KERNEL);
132	if (!vib)
133		return -ENOMEM;
134
135	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
136					  NULL);
137	if (IS_ERR(connection)) {
138		retval = PTR_ERR(connection);
139		goto err_free_vib;
140	}
141	gb_connection_set_data(connection, vib);
142
143	vib->connection = connection;
144
145	greybus_set_drvdata(bundle, vib);
146
147	retval = gb_connection_enable(connection);
148	if (retval)
149		goto err_connection_destroy;
150
151	/*
152	 * For now we create a device in sysfs for the vibrator, but odds are
153	 * there is a "real" device somewhere in the kernel for this, but I
154	 * can't find it at the moment...
155	 */
156	vib->minor = ida_alloc(&minors, GFP_KERNEL);
157	if (vib->minor < 0) {
158		retval = vib->minor;
159		goto err_connection_disable;
160	}
161	dev = device_create(&vibrator_class, &bundle->dev,
162			    MKDEV(0, 0), vib, "vibrator%d", vib->minor);
163	if (IS_ERR(dev)) {
164		retval = -EINVAL;
165		goto err_ida_remove;
166	}
167	vib->dev = dev;
168
169	INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker);
170
171	gb_pm_runtime_put_autosuspend(bundle);
172
173	return 0;
174
175err_ida_remove:
176	ida_free(&minors, vib->minor);
177err_connection_disable:
178	gb_connection_disable(connection);
179err_connection_destroy:
180	gb_connection_destroy(connection);
181err_free_vib:
182	kfree(vib);
183
184	return retval;
185}
186
187static void gb_vibrator_disconnect(struct gb_bundle *bundle)
188{
189	struct gb_vibrator_device *vib = greybus_get_drvdata(bundle);
190	int ret;
191
192	ret = gb_pm_runtime_get_sync(bundle);
193	if (ret)
194		gb_pm_runtime_get_noresume(bundle);
195
196	if (cancel_delayed_work_sync(&vib->delayed_work))
197		turn_off(vib);
198
199	device_unregister(vib->dev);
200	ida_free(&minors, vib->minor);
201	gb_connection_disable(vib->connection);
202	gb_connection_destroy(vib->connection);
203	kfree(vib);
204}
205
206static const struct greybus_bundle_id gb_vibrator_id_table[] = {
207	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
208	{ }
209};
210MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
211
212static struct greybus_driver gb_vibrator_driver = {
213	.name		= "vibrator",
214	.probe		= gb_vibrator_probe,
215	.disconnect	= gb_vibrator_disconnect,
216	.id_table	= gb_vibrator_id_table,
217};
218
219static __init int gb_vibrator_init(void)
220{
221	int retval;
222
223	retval = class_register(&vibrator_class);
224	if (retval)
225		return retval;
226
227	retval = greybus_register(&gb_vibrator_driver);
228	if (retval)
229		goto err_class_unregister;
230
231	return 0;
232
233err_class_unregister:
234	class_unregister(&vibrator_class);
235
236	return retval;
237}
238module_init(gb_vibrator_init);
239
240static __exit void gb_vibrator_exit(void)
241{
242	greybus_deregister(&gb_vibrator_driver);
243	class_unregister(&vibrator_class);
244	ida_destroy(&minors);
245}
246module_exit(gb_vibrator_exit);
247
248MODULE_LICENSE("GPL v2");
249