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 306d653370SAlex Elder /* Greybus Vibrator operation 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 3698abb414SViresh Kumar struct gb_vibrator_on_request { 3798abb414SViresh Kumar __le16 timeout_ms; 3898abb414SViresh Kumar }; 3998abb414SViresh Kumar 4036e79decSViresh Kumar /* Define get_version() routine */ 4136e79decSViresh Kumar define_get_version(gb_vibrator_device, VIBRATOR); 4298abb414SViresh Kumar 4398abb414SViresh Kumar static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) 4498abb414SViresh Kumar { 4598abb414SViresh Kumar struct gb_vibrator_on_request request; 4698abb414SViresh Kumar 4798abb414SViresh Kumar request.timeout_ms = cpu_to_le16(timeout_ms); 4898abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, 4998abb414SViresh Kumar &request, sizeof(request), NULL, 0); 5098abb414SViresh Kumar } 5198abb414SViresh Kumar 5298abb414SViresh Kumar static int turn_off(struct gb_vibrator_device *vib) 5398abb414SViresh Kumar { 5498abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, 5598abb414SViresh Kumar NULL, 0, NULL, 0); 5698abb414SViresh Kumar } 5798abb414SViresh Kumar 5898abb414SViresh Kumar static ssize_t timeout_store(struct device *dev, struct device_attribute *attr, 5998abb414SViresh Kumar const char *buf, size_t count) 6098abb414SViresh Kumar { 6198abb414SViresh Kumar struct gb_vibrator_device *vib = dev_get_drvdata(dev); 6298abb414SViresh Kumar unsigned long val; 6398abb414SViresh Kumar int retval; 6498abb414SViresh Kumar 6598abb414SViresh Kumar retval = kstrtoul(buf, 10, &val); 6698abb414SViresh Kumar if (retval < 0) { 6798abb414SViresh Kumar dev_err(dev, "could not parse timeout value %d\n", retval); 6898abb414SViresh Kumar return retval; 6998abb414SViresh Kumar } 7098abb414SViresh Kumar 7198abb414SViresh Kumar if (val) 7298abb414SViresh Kumar retval = turn_on(vib, (u16)val); 7398abb414SViresh Kumar else 7498abb414SViresh Kumar retval = turn_off(vib); 7598abb414SViresh Kumar if (retval) 7698abb414SViresh Kumar return retval; 7798abb414SViresh Kumar 7898abb414SViresh Kumar return count; 7998abb414SViresh Kumar } 8098abb414SViresh Kumar static DEVICE_ATTR_WO(timeout); 8198abb414SViresh Kumar 8298abb414SViresh Kumar static struct attribute *vibrator_attrs[] = { 8398abb414SViresh Kumar &dev_attr_timeout.attr, 8498abb414SViresh Kumar NULL, 8598abb414SViresh Kumar }; 8698abb414SViresh Kumar ATTRIBUTE_GROUPS(vibrator); 8798abb414SViresh Kumar 8898abb414SViresh Kumar static struct class vibrator_class = { 8998abb414SViresh Kumar .name = "vibrator", 9098abb414SViresh Kumar .owner = THIS_MODULE, 9198abb414SViresh Kumar #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) 9298abb414SViresh Kumar .dev_groups = vibrator_groups, 9398abb414SViresh Kumar #endif 9498abb414SViresh Kumar }; 9598abb414SViresh Kumar 966b17492eSGreg Kroah-Hartman static DEFINE_IDA(minors); 9798abb414SViresh Kumar 9898abb414SViresh Kumar static int gb_vibrator_connection_init(struct gb_connection *connection) 9998abb414SViresh Kumar { 10098abb414SViresh Kumar struct gb_vibrator_device *vib; 10198abb414SViresh Kumar struct device *dev; 10298abb414SViresh Kumar int retval; 10398abb414SViresh Kumar 10498abb414SViresh Kumar vib = kzalloc(sizeof(*vib), GFP_KERNEL); 10598abb414SViresh Kumar if (!vib) 10698abb414SViresh Kumar return -ENOMEM; 10798abb414SViresh Kumar 10898abb414SViresh Kumar vib->connection = connection; 10998abb414SViresh Kumar connection->private = vib; 11098abb414SViresh Kumar 11198abb414SViresh Kumar retval = get_version(vib); 11298abb414SViresh Kumar if (retval) 11398abb414SViresh Kumar goto error; 11498abb414SViresh Kumar 11598abb414SViresh Kumar /* 11698abb414SViresh Kumar * For now we create a device in sysfs for the vibrator, but odds are 11798abb414SViresh Kumar * there is a "real" device somewhere in the kernel for this, but I 11898abb414SViresh Kumar * can't find it at the moment... 11998abb414SViresh Kumar */ 1206b17492eSGreg Kroah-Hartman vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL); 12198abb414SViresh Kumar if (vib->minor < 0) { 12298abb414SViresh Kumar retval = vib->minor; 12398abb414SViresh Kumar goto error; 12498abb414SViresh Kumar } 12598abb414SViresh Kumar dev = device_create(&vibrator_class, &connection->dev, MKDEV(0, 0), vib, 12698abb414SViresh Kumar "vibrator%d", vib->minor); 12798abb414SViresh Kumar if (IS_ERR(dev)) { 12898abb414SViresh Kumar retval = -EINVAL; 1296b17492eSGreg Kroah-Hartman goto err_ida_remove; 13098abb414SViresh Kumar } 13198abb414SViresh Kumar vib->dev = dev; 13298abb414SViresh Kumar 13398abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 13498abb414SViresh Kumar /* 13598abb414SViresh Kumar * Newer kernels handle this in a race-free manner, by the dev_groups 13698abb414SViresh Kumar * field in the struct class up above. But for older kernels, we need 13798abb414SViresh Kumar * to "open code this :( 13898abb414SViresh Kumar */ 13998abb414SViresh Kumar retval = sysfs_create_group(&dev->kobj, vibrator_groups[0]); 14098abb414SViresh Kumar if (retval) { 14198abb414SViresh Kumar device_unregister(dev); 1426b17492eSGreg Kroah-Hartman goto err_ida_remove; 14398abb414SViresh Kumar } 14498abb414SViresh Kumar #endif 14598abb414SViresh Kumar 14698abb414SViresh Kumar return 0; 14798abb414SViresh Kumar 1486b17492eSGreg Kroah-Hartman err_ida_remove: 1496b17492eSGreg Kroah-Hartman ida_simple_remove(&minors, vib->minor); 15098abb414SViresh Kumar error: 15198abb414SViresh Kumar kfree(vib); 15298abb414SViresh Kumar return retval; 15398abb414SViresh Kumar } 15498abb414SViresh Kumar 15598abb414SViresh Kumar static void gb_vibrator_connection_exit(struct gb_connection *connection) 15698abb414SViresh Kumar { 15798abb414SViresh Kumar struct gb_vibrator_device *vib = connection->private; 15898abb414SViresh Kumar 15998abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 16098abb414SViresh Kumar sysfs_remove_group(&vib->dev->kobj, vibrator_groups[0]); 16198abb414SViresh Kumar #endif 1626b17492eSGreg Kroah-Hartman ida_simple_remove(&minors, vib->minor); 16398abb414SViresh Kumar device_unregister(vib->dev); 16498abb414SViresh Kumar kfree(vib); 16598abb414SViresh Kumar } 16698abb414SViresh Kumar 16798abb414SViresh Kumar static struct gb_protocol vibrator_protocol = { 16898abb414SViresh Kumar .name = "vibrator", 16998abb414SViresh Kumar .id = GREYBUS_PROTOCOL_VIBRATOR, 17098abb414SViresh Kumar .major = 0, 17198abb414SViresh Kumar .minor = 1, 17298abb414SViresh Kumar .connection_init = gb_vibrator_connection_init, 17398abb414SViresh Kumar .connection_exit = gb_vibrator_connection_exit, 17498abb414SViresh Kumar .request_recv = NULL, /* no incoming requests */ 17598abb414SViresh Kumar }; 17698abb414SViresh Kumar 17798abb414SViresh Kumar static __init int protocol_init(void) 17898abb414SViresh Kumar { 17998abb414SViresh Kumar int retval; 18098abb414SViresh Kumar 18198abb414SViresh Kumar retval = class_register(&vibrator_class); 18298abb414SViresh Kumar if (retval) 18398abb414SViresh Kumar return retval; 18498abb414SViresh Kumar 18598abb414SViresh Kumar return gb_protocol_register(&vibrator_protocol); 18698abb414SViresh Kumar } 1870d34be75SViresh Kumar module_init(protocol_init); 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); 1935c1ac694SGreg Kroah-Hartman ida_destroy(&minors); 19498abb414SViresh Kumar } 19598abb414SViresh Kumar module_exit(protocol_exit); 19698abb414SViresh Kumar 19798abb414SViresh Kumar MODULE_LICENSE("GPL v2"); 198