blob: 04737c80496dd95edaff0f0c376c6c437b98c6b3 [file] [log] [blame]
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -08001/*
Greg Kroah-Hartman4efe6062014-11-17 16:55:54 -08002 * Greybus Vibrator protocol driver.
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -08003 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 Linaro Ltd.
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -08006 *
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>
Greg Kroah-Hartman396671b2014-11-17 17:12:50 -080015#include <linux/idr.h>
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080016#include "greybus.h"
17
18struct gb_vibrator_device {
19 struct gb_connection *connection;
20 struct device *dev;
Greg Kroah-Hartman396671b2014-11-17 17:12:50 -080021 int minor; /* vibrator minor number */
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080022};
23
Greg Kroah-Hartman42a94662014-11-19 10:36:23 -080024/* Version of the Greybus vibrator protocol we support */
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080025#define GB_VIBRATOR_VERSION_MAJOR 0x00
26#define GB_VIBRATOR_VERSION_MINOR 0x01
27
Alex Elder6d653372015-05-07 13:03:52 -050028/* Greybus Vibrator operation types */
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080029#define GB_VIBRATOR_TYPE_ON 0x02
30#define GB_VIBRATOR_TYPE_OFF 0x03
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080031
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080032struct gb_vibrator_on_request {
33 __le16 timeout_ms;
34};
35
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080036static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
37{
Greg Kroah-Hartmanac3d2492014-11-23 17:45:20 -080038 struct gb_vibrator_on_request request;
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080039
Greg Kroah-Hartmanac3d2492014-11-23 17:45:20 -080040 request.timeout_ms = cpu_to_le16(timeout_ms);
41 return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON,
42 &request, sizeof(request), NULL, 0);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080043}
44
45static int turn_off(struct gb_vibrator_device *vib)
46{
Greg Kroah-Hartmanac3d2492014-11-23 17:45:20 -080047 return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF,
48 NULL, 0, NULL, 0);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080049}
50
51static ssize_t timeout_store(struct device *dev, struct device_attribute *attr,
52 const char *buf, size_t count)
53{
54 struct gb_vibrator_device *vib = dev_get_drvdata(dev);
55 unsigned long val;
56 int retval;
57
58 retval = kstrtoul(buf, 10, &val);
59 if (retval < 0) {
60 dev_err(dev, "could not parse timeout value %d\n", retval);
61 return retval;
62 }
63
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080064 if (val)
65 retval = turn_on(vib, (u16)val);
66 else
67 retval = turn_off(vib);
68 if (retval)
69 return retval;
70
71 return count;
72}
73static DEVICE_ATTR_WO(timeout);
74
75static struct attribute *vibrator_attrs[] = {
76 &dev_attr_timeout.attr,
77 NULL,
78};
79ATTRIBUTE_GROUPS(vibrator);
80
81static struct class vibrator_class = {
82 .name = "vibrator",
83 .owner = THIS_MODULE,
84#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
85 .dev_groups = vibrator_groups,
86#endif
87};
88
Greg Kroah-Hartman6b174922015-05-14 10:39:35 -070089static DEFINE_IDA(minors);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080090
91static int gb_vibrator_connection_init(struct gb_connection *connection)
92{
93 struct gb_vibrator_device *vib;
94 struct device *dev;
95 int retval;
96
97 vib = kzalloc(sizeof(*vib), GFP_KERNEL);
98 if (!vib)
99 return -ENOMEM;
100
101 vib->connection = connection;
Alex Elder93bbe852014-12-03 12:27:42 -0600102 connection->private = vib;
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800103
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800104 /*
Greg Kroah-Hartman396671b2014-11-17 17:12:50 -0800105 * For now we create a device in sysfs for the vibrator, but odds are
106 * there is a "real" device somewhere in the kernel for this, but I
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800107 * can't find it at the moment...
108 */
Greg Kroah-Hartman6b174922015-05-14 10:39:35 -0700109 vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
Greg Kroah-Hartman396671b2014-11-17 17:12:50 -0800110 if (vib->minor < 0) {
111 retval = vib->minor;
112 goto error;
113 }
Greg Kroah-Hartman5ae2f552015-10-14 11:12:06 -0700114 dev = device_create(&vibrator_class, &connection->bundle->dev,
115 MKDEV(0, 0), vib, "vibrator%d", vib->minor);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800116 if (IS_ERR(dev)) {
117 retval = -EINVAL;
Greg Kroah-Hartman6b174922015-05-14 10:39:35 -0700118 goto err_ida_remove;
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800119 }
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800120 vib->dev = dev;
121
122#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0)
123 /*
Greg Kroah-Hartman4efe6062014-11-17 16:55:54 -0800124 * Newer kernels handle this in a race-free manner, by the dev_groups
125 * field in the struct class up above. But for older kernels, we need
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800126 * to "open code this :(
127 */
128 retval = sysfs_create_group(&dev->kobj, vibrator_groups[0]);
129 if (retval) {
130 device_unregister(dev);
Greg Kroah-Hartman6b174922015-05-14 10:39:35 -0700131 goto err_ida_remove;
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800132 }
133#endif
134
135 return 0;
136
Greg Kroah-Hartman6b174922015-05-14 10:39:35 -0700137err_ida_remove:
138 ida_simple_remove(&minors, vib->minor);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800139error:
140 kfree(vib);
141 return retval;
142}
143
144static void gb_vibrator_connection_exit(struct gb_connection *connection)
145{
146 struct gb_vibrator_device *vib = connection->private;
147
148#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0)
149 sysfs_remove_group(&vib->dev->kobj, vibrator_groups[0]);
150#endif
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800151 device_unregister(vib->dev);
Johan Hovoldd7849bf2015-09-14 20:19:02 +0200152 ida_simple_remove(&minors, vib->minor);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800153 kfree(vib);
154}
155
156static struct gb_protocol vibrator_protocol = {
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -0800157 .name = "vibrator",
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800158 .id = GREYBUS_PROTOCOL_VIBRATOR,
Viresh Kumarf0a16982015-08-08 10:25:41 +0530159 .major = GB_VIBRATOR_VERSION_MAJOR,
160 .minor = GB_VIBRATOR_VERSION_MINOR,
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800161 .connection_init = gb_vibrator_connection_init,
162 .connection_exit = gb_vibrator_connection_exit,
163 .request_recv = NULL, /* no incoming requests */
164};
165
Greg Kroah-Hartman66b676f2014-12-24 13:01:41 -0800166static __init int protocol_init(void)
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800167{
168 int retval;
169
170 retval = class_register(&vibrator_class);
171 if (retval)
172 return retval;
173
Johan Hovoldd4efa682015-10-13 19:10:27 +0200174 retval = gb_protocol_register(&vibrator_protocol);
175 if (retval)
176 goto err_class_unregister;
177
178 return 0;
179
180err_class_unregister:
181 class_unregister(&vibrator_class);
182
183 return retval;
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800184}
Viresh Kumar0d34be72015-03-24 20:14:28 +0530185module_init(protocol_init);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800186
Greg Kroah-Hartman66b676f2014-12-24 13:01:41 -0800187static __exit void protocol_exit(void)
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800188{
189 gb_protocol_deregister(&vibrator_protocol);
190 class_unregister(&vibrator_class);
Greg Kroah-Hartman5c1ac692015-07-08 10:44:09 -0700191 ida_destroy(&minors);
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -0800192}
Greg Kroah-Hartman66b676f2014-12-24 13:01:41 -0800193module_exit(protocol_exit);
194
195MODULE_LICENSE("GPL v2");