198abb414SViresh Kumar /* 298abb414SViresh Kumar * Greybus Vibrator protocol driver. 398abb414SViresh Kumar * 498abb414SViresh Kumar * Copyright 2014 Google Inc. 598abb414SViresh Kumar * Copyright 2014 Linaro Ltd. 698abb414SViresh Kumar * 798abb414SViresh Kumar * Released under the GPLv2 only. 898abb414SViresh Kumar */ 998abb414SViresh Kumar 1098abb414SViresh Kumar #include <linux/kernel.h> 1198abb414SViresh Kumar #include <linux/module.h> 1298abb414SViresh Kumar #include <linux/slab.h> 1398abb414SViresh Kumar #include <linux/device.h> 1498abb414SViresh Kumar #include <linux/kdev_t.h> 1598abb414SViresh Kumar #include <linux/idr.h> 1698abb414SViresh Kumar #include "greybus.h" 1798abb414SViresh Kumar 1898abb414SViresh Kumar struct gb_vibrator_device { 1998abb414SViresh Kumar struct gb_connection *connection; 2098abb414SViresh Kumar struct device *dev; 2198abb414SViresh Kumar int minor; /* vibrator minor number */ 2298abb414SViresh Kumar u8 version_major; 2398abb414SViresh Kumar u8 version_minor; 2498abb414SViresh Kumar }; 2598abb414SViresh Kumar 2698abb414SViresh Kumar /* Version of the Greybus vibrator protocol we support */ 2798abb414SViresh Kumar #define GB_VIBRATOR_VERSION_MAJOR 0x00 2898abb414SViresh Kumar #define GB_VIBRATOR_VERSION_MINOR 0x01 2998abb414SViresh Kumar 3098abb414SViresh Kumar /* Greybus Vibrator request types */ 3198abb414SViresh Kumar #define GB_VIBRATOR_TYPE_INVALID 0x00 3298abb414SViresh Kumar #define GB_VIBRATOR_TYPE_PROTOCOL_VERSION 0x01 3398abb414SViresh Kumar #define GB_VIBRATOR_TYPE_ON 0x02 3498abb414SViresh Kumar #define GB_VIBRATOR_TYPE_OFF 0x03 3598abb414SViresh Kumar #define GB_VIBRATOR_TYPE_RESPONSE 0x80 /* OR'd with rest */ 3698abb414SViresh Kumar 3798abb414SViresh Kumar struct gb_vibrator_on_request { 3898abb414SViresh Kumar __le16 timeout_ms; 3998abb414SViresh Kumar }; 4098abb414SViresh Kumar 4136e79decSViresh Kumar /* Define get_version() routine */ 4236e79decSViresh Kumar define_get_version(gb_vibrator_device, VIBRATOR); 4398abb414SViresh Kumar 4498abb414SViresh Kumar static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) 4598abb414SViresh Kumar { 4698abb414SViresh Kumar struct gb_vibrator_on_request request; 4798abb414SViresh Kumar 4898abb414SViresh Kumar request.timeout_ms = cpu_to_le16(timeout_ms); 4998abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, 5098abb414SViresh Kumar &request, sizeof(request), NULL, 0); 5198abb414SViresh Kumar } 5298abb414SViresh Kumar 5398abb414SViresh Kumar static int turn_off(struct gb_vibrator_device *vib) 5498abb414SViresh Kumar { 5598abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, 5698abb414SViresh Kumar NULL, 0, NULL, 0); 5798abb414SViresh Kumar } 5898abb414SViresh Kumar 5998abb414SViresh Kumar static ssize_t timeout_store(struct device *dev, struct device_attribute *attr, 6098abb414SViresh Kumar const char *buf, size_t count) 6198abb414SViresh Kumar { 6298abb414SViresh Kumar struct gb_vibrator_device *vib = dev_get_drvdata(dev); 6398abb414SViresh Kumar unsigned long val; 6498abb414SViresh Kumar int retval; 6598abb414SViresh Kumar 6698abb414SViresh Kumar retval = kstrtoul(buf, 10, &val); 6798abb414SViresh Kumar if (retval < 0) { 6898abb414SViresh Kumar dev_err(dev, "could not parse timeout value %d\n", retval); 6998abb414SViresh Kumar return retval; 7098abb414SViresh Kumar } 7198abb414SViresh Kumar 7298abb414SViresh Kumar if (val) 7398abb414SViresh Kumar retval = turn_on(vib, (u16)val); 7498abb414SViresh Kumar else 7598abb414SViresh Kumar retval = turn_off(vib); 7698abb414SViresh Kumar if (retval) 7798abb414SViresh Kumar return retval; 7898abb414SViresh Kumar 7998abb414SViresh Kumar return count; 8098abb414SViresh Kumar } 8198abb414SViresh Kumar static DEVICE_ATTR_WO(timeout); 8298abb414SViresh Kumar 8398abb414SViresh Kumar static struct attribute *vibrator_attrs[] = { 8498abb414SViresh Kumar &dev_attr_timeout.attr, 8598abb414SViresh Kumar NULL, 8698abb414SViresh Kumar }; 8798abb414SViresh Kumar ATTRIBUTE_GROUPS(vibrator); 8898abb414SViresh Kumar 8998abb414SViresh Kumar static struct class vibrator_class = { 9098abb414SViresh Kumar .name = "vibrator", 9198abb414SViresh Kumar .owner = THIS_MODULE, 9298abb414SViresh Kumar #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) 9398abb414SViresh Kumar .dev_groups = vibrator_groups, 9498abb414SViresh Kumar #endif 9598abb414SViresh Kumar }; 9698abb414SViresh Kumar 9798abb414SViresh Kumar static DEFINE_IDR(minors); 9898abb414SViresh Kumar 9998abb414SViresh Kumar static int gb_vibrator_connection_init(struct gb_connection *connection) 10098abb414SViresh Kumar { 10198abb414SViresh Kumar struct gb_vibrator_device *vib; 10298abb414SViresh Kumar struct device *dev; 10398abb414SViresh Kumar int retval; 10498abb414SViresh Kumar 10598abb414SViresh Kumar vib = kzalloc(sizeof(*vib), GFP_KERNEL); 10698abb414SViresh Kumar if (!vib) 10798abb414SViresh Kumar return -ENOMEM; 10898abb414SViresh Kumar 10998abb414SViresh Kumar vib->connection = connection; 11098abb414SViresh Kumar connection->private = vib; 11198abb414SViresh Kumar 11298abb414SViresh Kumar retval = get_version(vib); 11398abb414SViresh Kumar if (retval) 11498abb414SViresh Kumar goto error; 11598abb414SViresh Kumar 11698abb414SViresh Kumar /* 11798abb414SViresh Kumar * For now we create a device in sysfs for the vibrator, but odds are 11898abb414SViresh Kumar * there is a "real" device somewhere in the kernel for this, but I 11998abb414SViresh Kumar * can't find it at the moment... 12098abb414SViresh Kumar */ 12198abb414SViresh Kumar vib->minor = idr_alloc(&minors, vib, 0, 0, GFP_KERNEL); 12298abb414SViresh Kumar if (vib->minor < 0) { 12398abb414SViresh Kumar retval = vib->minor; 12498abb414SViresh Kumar goto error; 12598abb414SViresh Kumar } 12698abb414SViresh Kumar dev = device_create(&vibrator_class, &connection->dev, MKDEV(0, 0), vib, 12798abb414SViresh Kumar "vibrator%d", vib->minor); 12898abb414SViresh Kumar if (IS_ERR(dev)) { 12998abb414SViresh Kumar retval = -EINVAL; 130deeb57f5SJohan Hovold goto err_idr_remove; 13198abb414SViresh Kumar } 13298abb414SViresh Kumar vib->dev = dev; 13398abb414SViresh Kumar 13498abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 13598abb414SViresh Kumar /* 13698abb414SViresh Kumar * Newer kernels handle this in a race-free manner, by the dev_groups 13798abb414SViresh Kumar * field in the struct class up above. But for older kernels, we need 13898abb414SViresh Kumar * to "open code this :( 13998abb414SViresh Kumar */ 14098abb414SViresh Kumar retval = sysfs_create_group(&dev->kobj, vibrator_groups[0]); 14198abb414SViresh Kumar if (retval) { 14298abb414SViresh Kumar device_unregister(dev); 143deeb57f5SJohan Hovold goto err_idr_remove; 14498abb414SViresh Kumar } 14598abb414SViresh Kumar #endif 14698abb414SViresh Kumar 14798abb414SViresh Kumar return 0; 14898abb414SViresh Kumar 149deeb57f5SJohan Hovold err_idr_remove: 150deeb57f5SJohan Hovold idr_remove(&minors, vib->minor); 15198abb414SViresh Kumar error: 15298abb414SViresh Kumar kfree(vib); 15398abb414SViresh Kumar return retval; 15498abb414SViresh Kumar } 15598abb414SViresh Kumar 15698abb414SViresh Kumar static void gb_vibrator_connection_exit(struct gb_connection *connection) 15798abb414SViresh Kumar { 15898abb414SViresh Kumar struct gb_vibrator_device *vib = connection->private; 15998abb414SViresh Kumar 16098abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 16198abb414SViresh Kumar sysfs_remove_group(&vib->dev->kobj, vibrator_groups[0]); 16298abb414SViresh Kumar #endif 16398abb414SViresh Kumar idr_remove(&minors, vib->minor); 16498abb414SViresh Kumar device_unregister(vib->dev); 16598abb414SViresh Kumar kfree(vib); 16698abb414SViresh Kumar } 16798abb414SViresh Kumar 16898abb414SViresh Kumar static struct gb_protocol vibrator_protocol = { 16998abb414SViresh Kumar .name = "vibrator", 17098abb414SViresh Kumar .id = GREYBUS_PROTOCOL_VIBRATOR, 17198abb414SViresh Kumar .major = 0, 17298abb414SViresh Kumar .minor = 1, 17398abb414SViresh Kumar .connection_init = gb_vibrator_connection_init, 17498abb414SViresh Kumar .connection_exit = gb_vibrator_connection_exit, 17598abb414SViresh Kumar .request_recv = NULL, /* no incoming requests */ 17698abb414SViresh Kumar }; 17798abb414SViresh Kumar 17898abb414SViresh Kumar static __init int protocol_init(void) 17998abb414SViresh Kumar { 18098abb414SViresh Kumar int retval; 18198abb414SViresh Kumar 18298abb414SViresh Kumar retval = class_register(&vibrator_class); 18398abb414SViresh Kumar if (retval) 18498abb414SViresh Kumar return retval; 18598abb414SViresh Kumar 18698abb414SViresh Kumar return gb_protocol_register(&vibrator_protocol); 18798abb414SViresh Kumar } 18898abb414SViresh Kumar 18998abb414SViresh Kumar static __exit void protocol_exit(void) 19098abb414SViresh Kumar { 19198abb414SViresh Kumar gb_protocol_deregister(&vibrator_protocol); 19298abb414SViresh Kumar class_unregister(&vibrator_class); 19398abb414SViresh Kumar } 19498abb414SViresh Kumar 19598abb414SViresh Kumar module_init(protocol_init); 19698abb414SViresh Kumar module_exit(protocol_exit); 19798abb414SViresh Kumar 19898abb414SViresh Kumar MODULE_LICENSE("GPL v2"); 199