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 }; 2398abb414SViresh Kumar 2498abb414SViresh Kumar /* Version of the Greybus vibrator protocol we support */ 2598abb414SViresh Kumar #define GB_VIBRATOR_VERSION_MAJOR 0x00 2698abb414SViresh Kumar #define GB_VIBRATOR_VERSION_MINOR 0x01 2798abb414SViresh Kumar 286d653370SAlex Elder /* Greybus Vibrator operation types */ 2998abb414SViresh Kumar #define GB_VIBRATOR_TYPE_ON 0x02 3098abb414SViresh Kumar #define GB_VIBRATOR_TYPE_OFF 0x03 3198abb414SViresh Kumar 3298abb414SViresh Kumar struct gb_vibrator_on_request { 3398abb414SViresh Kumar __le16 timeout_ms; 3498abb414SViresh Kumar }; 3598abb414SViresh Kumar 3698abb414SViresh Kumar static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) 3798abb414SViresh Kumar { 3898abb414SViresh Kumar struct gb_vibrator_on_request request; 3998abb414SViresh Kumar 4098abb414SViresh Kumar request.timeout_ms = cpu_to_le16(timeout_ms); 4198abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, 4298abb414SViresh Kumar &request, sizeof(request), NULL, 0); 4398abb414SViresh Kumar } 4498abb414SViresh Kumar 4598abb414SViresh Kumar static int turn_off(struct gb_vibrator_device *vib) 4698abb414SViresh Kumar { 4798abb414SViresh Kumar return gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, 4898abb414SViresh Kumar NULL, 0, NULL, 0); 4998abb414SViresh Kumar } 5098abb414SViresh Kumar 5198abb414SViresh Kumar static ssize_t timeout_store(struct device *dev, struct device_attribute *attr, 5298abb414SViresh Kumar const char *buf, size_t count) 5398abb414SViresh Kumar { 5498abb414SViresh Kumar struct gb_vibrator_device *vib = dev_get_drvdata(dev); 5598abb414SViresh Kumar unsigned long val; 5698abb414SViresh Kumar int retval; 5798abb414SViresh Kumar 5898abb414SViresh Kumar retval = kstrtoul(buf, 10, &val); 5998abb414SViresh Kumar if (retval < 0) { 6098abb414SViresh Kumar dev_err(dev, "could not parse timeout value %d\n", retval); 6198abb414SViresh Kumar return retval; 6298abb414SViresh Kumar } 6398abb414SViresh Kumar 6498abb414SViresh Kumar if (val) 6598abb414SViresh Kumar retval = turn_on(vib, (u16)val); 6698abb414SViresh Kumar else 6798abb414SViresh Kumar retval = turn_off(vib); 6898abb414SViresh Kumar if (retval) 6998abb414SViresh Kumar return retval; 7098abb414SViresh Kumar 7198abb414SViresh Kumar return count; 7298abb414SViresh Kumar } 7398abb414SViresh Kumar static DEVICE_ATTR_WO(timeout); 7498abb414SViresh Kumar 7598abb414SViresh Kumar static struct attribute *vibrator_attrs[] = { 7698abb414SViresh Kumar &dev_attr_timeout.attr, 7798abb414SViresh Kumar NULL, 7898abb414SViresh Kumar }; 7998abb414SViresh Kumar ATTRIBUTE_GROUPS(vibrator); 8098abb414SViresh Kumar 8198abb414SViresh Kumar static struct class vibrator_class = { 8298abb414SViresh Kumar .name = "vibrator", 8398abb414SViresh Kumar .owner = THIS_MODULE, 8498abb414SViresh Kumar #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) 8598abb414SViresh Kumar .dev_groups = vibrator_groups, 8698abb414SViresh Kumar #endif 8798abb414SViresh Kumar }; 8898abb414SViresh Kumar 896b17492eSGreg Kroah-Hartman static DEFINE_IDA(minors); 9098abb414SViresh Kumar 9198abb414SViresh Kumar static int gb_vibrator_connection_init(struct gb_connection *connection) 9298abb414SViresh Kumar { 9398abb414SViresh Kumar struct gb_vibrator_device *vib; 9498abb414SViresh Kumar struct device *dev; 9598abb414SViresh Kumar int retval; 9698abb414SViresh Kumar 9798abb414SViresh Kumar vib = kzalloc(sizeof(*vib), GFP_KERNEL); 9898abb414SViresh Kumar if (!vib) 9998abb414SViresh Kumar return -ENOMEM; 10098abb414SViresh Kumar 10198abb414SViresh Kumar vib->connection = connection; 10298abb414SViresh Kumar connection->private = vib; 10398abb414SViresh Kumar 10498abb414SViresh Kumar /* 10598abb414SViresh Kumar * For now we create a device in sysfs for the vibrator, but odds are 10698abb414SViresh Kumar * there is a "real" device somewhere in the kernel for this, but I 10798abb414SViresh Kumar * can't find it at the moment... 10898abb414SViresh Kumar */ 1096b17492eSGreg Kroah-Hartman vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL); 11098abb414SViresh Kumar if (vib->minor < 0) { 11198abb414SViresh Kumar retval = vib->minor; 11298abb414SViresh Kumar goto error; 11398abb414SViresh Kumar } 11498abb414SViresh Kumar dev = device_create(&vibrator_class, &connection->dev, MKDEV(0, 0), vib, 11598abb414SViresh Kumar "vibrator%d", vib->minor); 11698abb414SViresh Kumar if (IS_ERR(dev)) { 11798abb414SViresh Kumar retval = -EINVAL; 1186b17492eSGreg Kroah-Hartman goto err_ida_remove; 11998abb414SViresh Kumar } 12098abb414SViresh Kumar vib->dev = dev; 12198abb414SViresh Kumar 12298abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 12398abb414SViresh Kumar /* 12498abb414SViresh Kumar * Newer kernels handle this in a race-free manner, by the dev_groups 12598abb414SViresh Kumar * field in the struct class up above. But for older kernels, we need 12698abb414SViresh Kumar * to "open code this :( 12798abb414SViresh Kumar */ 12898abb414SViresh Kumar retval = sysfs_create_group(&dev->kobj, vibrator_groups[0]); 12998abb414SViresh Kumar if (retval) { 13098abb414SViresh Kumar device_unregister(dev); 1316b17492eSGreg Kroah-Hartman goto err_ida_remove; 13298abb414SViresh Kumar } 13398abb414SViresh Kumar #endif 13498abb414SViresh Kumar 13598abb414SViresh Kumar return 0; 13698abb414SViresh Kumar 1376b17492eSGreg Kroah-Hartman err_ida_remove: 1386b17492eSGreg Kroah-Hartman ida_simple_remove(&minors, vib->minor); 13998abb414SViresh Kumar error: 14098abb414SViresh Kumar kfree(vib); 14198abb414SViresh Kumar return retval; 14298abb414SViresh Kumar } 14398abb414SViresh Kumar 14498abb414SViresh Kumar static void gb_vibrator_connection_exit(struct gb_connection *connection) 14598abb414SViresh Kumar { 14698abb414SViresh Kumar struct gb_vibrator_device *vib = connection->private; 14798abb414SViresh Kumar 14898abb414SViresh Kumar #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) 14998abb414SViresh Kumar sysfs_remove_group(&vib->dev->kobj, vibrator_groups[0]); 15098abb414SViresh Kumar #endif 15198abb414SViresh Kumar device_unregister(vib->dev); 152d7849bffSJohan Hovold ida_simple_remove(&minors, vib->minor); 15398abb414SViresh Kumar kfree(vib); 15498abb414SViresh Kumar } 15598abb414SViresh Kumar 15698abb414SViresh Kumar static struct gb_protocol vibrator_protocol = { 15798abb414SViresh Kumar .name = "vibrator", 15898abb414SViresh Kumar .id = GREYBUS_PROTOCOL_VIBRATOR, 159f0a1698fSViresh Kumar .major = GB_VIBRATOR_VERSION_MAJOR, 160f0a1698fSViresh Kumar .minor = GB_VIBRATOR_VERSION_MINOR, 16198abb414SViresh Kumar .connection_init = gb_vibrator_connection_init, 16298abb414SViresh Kumar .connection_exit = gb_vibrator_connection_exit, 16398abb414SViresh Kumar .request_recv = NULL, /* no incoming requests */ 16498abb414SViresh Kumar }; 16598abb414SViresh Kumar 16698abb414SViresh Kumar static __init int protocol_init(void) 16798abb414SViresh Kumar { 16898abb414SViresh Kumar int retval; 16998abb414SViresh Kumar 17098abb414SViresh Kumar retval = class_register(&vibrator_class); 17198abb414SViresh Kumar if (retval) 17298abb414SViresh Kumar return retval; 17398abb414SViresh Kumar 174d4efa688SJohan Hovold retval = gb_protocol_register(&vibrator_protocol); 175d4efa688SJohan Hovold if (retval) 176d4efa688SJohan Hovold goto err_class_unregister; 177d4efa688SJohan Hovold 178d4efa688SJohan Hovold return 0; 179d4efa688SJohan Hovold 180d4efa688SJohan Hovold err_class_unregister: 181d4efa688SJohan Hovold class_unregister(&vibrator_class); 182d4efa688SJohan Hovold 183d4efa688SJohan Hovold return retval; 18498abb414SViresh Kumar } 1850d34be75SViresh Kumar module_init(protocol_init); 18698abb414SViresh Kumar 18798abb414SViresh Kumar static __exit void protocol_exit(void) 18898abb414SViresh Kumar { 18998abb414SViresh Kumar gb_protocol_deregister(&vibrator_protocol); 19098abb414SViresh Kumar class_unregister(&vibrator_class); 1915c1ac694SGreg Kroah-Hartman ida_destroy(&minors); 19298abb414SViresh Kumar } 19398abb414SViresh Kumar module_exit(protocol_exit); 19498abb414SViresh Kumar 19598abb414SViresh Kumar MODULE_LICENSE("GPL v2"); 196