1 /* 2 * Greybus Vibrator protocol driver. 3 * 4 * Copyright 2014 Google Inc. 5 * Copyright 2014 Linaro Ltd. 6 * 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> 15 #include <linux/idr.h> 16 #include <linux/pm_runtime.h> 17 18 #include "greybus.h" 19 20 struct gb_vibrator_device { 21 struct gb_connection *connection; 22 struct device *dev; 23 int minor; /* vibrator minor number */ 24 struct delayed_work delayed_work; 25 }; 26 27 /* Greybus Vibrator operation types */ 28 #define GB_VIBRATOR_TYPE_ON 0x02 29 #define GB_VIBRATOR_TYPE_OFF 0x03 30 31 static int turn_off(struct gb_vibrator_device *vib) 32 { 33 struct gb_bundle *bundle = vib->connection->bundle; 34 int ret; 35 36 ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, 37 NULL, 0, NULL, 0); 38 39 gb_pm_runtime_put_autosuspend(bundle); 40 41 return ret; 42 } 43 44 static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) 45 { 46 struct gb_bundle *bundle = vib->connection->bundle; 47 int ret; 48 49 ret = gb_pm_runtime_get_sync(bundle); 50 if (ret) 51 return ret; 52 53 /* Vibrator was switched ON earlier */ 54 if (cancel_delayed_work_sync(&vib->delayed_work)) 55 turn_off(vib); 56 57 ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, 58 NULL, 0, NULL, 0); 59 if (ret) { 60 gb_pm_runtime_put_autosuspend(bundle); 61 return ret; 62 } 63 64 schedule_delayed_work(&vib->delayed_work, msecs_to_jiffies(timeout_ms)); 65 66 return 0; 67 } 68 69 static void gb_vibrator_worker(struct work_struct *work) 70 { 71 struct delayed_work *delayed_work = to_delayed_work(work); 72 struct gb_vibrator_device *vib = 73 container_of(delayed_work, 74 struct gb_vibrator_device, 75 delayed_work); 76 77 turn_off(vib); 78 } 79 80 static ssize_t timeout_store(struct device *dev, struct device_attribute *attr, 81 const char *buf, size_t count) 82 { 83 struct gb_vibrator_device *vib = dev_get_drvdata(dev); 84 unsigned long val; 85 int retval; 86 87 retval = kstrtoul(buf, 10, &val); 88 if (retval < 0) { 89 dev_err(dev, "could not parse timeout value %d\n", retval); 90 return retval; 91 } 92 93 if (val) 94 retval = turn_on(vib, (u16)val); 95 else 96 retval = turn_off(vib); 97 if (retval) 98 return retval; 99 100 return count; 101 } 102 static DEVICE_ATTR_WO(timeout); 103 104 static struct attribute *vibrator_attrs[] = { 105 &dev_attr_timeout.attr, 106 NULL, 107 }; 108 ATTRIBUTE_GROUPS(vibrator); 109 110 static struct class vibrator_class = { 111 .name = "vibrator", 112 .owner = THIS_MODULE, 113 .dev_groups = vibrator_groups, 114 }; 115 116 static DEFINE_IDA(minors); 117 118 static int gb_vibrator_probe(struct gb_bundle *bundle, 119 const struct greybus_bundle_id *id) 120 { 121 struct greybus_descriptor_cport *cport_desc; 122 struct gb_connection *connection; 123 struct gb_vibrator_device *vib; 124 struct device *dev; 125 int retval; 126 127 if (bundle->num_cports != 1) 128 return -ENODEV; 129 130 cport_desc = &bundle->cport_desc[0]; 131 if (cport_desc->protocol_id != GREYBUS_PROTOCOL_VIBRATOR) 132 return -ENODEV; 133 134 vib = kzalloc(sizeof(*vib), GFP_KERNEL); 135 if (!vib) 136 return -ENOMEM; 137 138 connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), 139 NULL); 140 if (IS_ERR(connection)) { 141 retval = PTR_ERR(connection); 142 goto err_free_vib; 143 } 144 gb_connection_set_data(connection, vib); 145 146 vib->connection = connection; 147 148 greybus_set_drvdata(bundle, vib); 149 150 retval = gb_connection_enable(connection); 151 if (retval) 152 goto err_connection_destroy; 153 154 /* 155 * For now we create a device in sysfs for the vibrator, but odds are 156 * there is a "real" device somewhere in the kernel for this, but I 157 * can't find it at the moment... 158 */ 159 vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL); 160 if (vib->minor < 0) { 161 retval = vib->minor; 162 goto err_connection_disable; 163 } 164 dev = device_create(&vibrator_class, &bundle->dev, 165 MKDEV(0, 0), vib, "vibrator%d", vib->minor); 166 if (IS_ERR(dev)) { 167 retval = -EINVAL; 168 goto err_ida_remove; 169 } 170 vib->dev = dev; 171 172 INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker); 173 174 gb_pm_runtime_put_autosuspend(bundle); 175 176 return 0; 177 178 err_ida_remove: 179 ida_simple_remove(&minors, vib->minor); 180 err_connection_disable: 181 gb_connection_disable(connection); 182 err_connection_destroy: 183 gb_connection_destroy(connection); 184 err_free_vib: 185 kfree(vib); 186 187 return retval; 188 } 189 190 static void gb_vibrator_disconnect(struct gb_bundle *bundle) 191 { 192 struct gb_vibrator_device *vib = greybus_get_drvdata(bundle); 193 int ret; 194 195 ret = gb_pm_runtime_get_sync(bundle); 196 if (ret) 197 gb_pm_runtime_get_noresume(bundle); 198 199 if (cancel_delayed_work_sync(&vib->delayed_work)) 200 turn_off(vib); 201 202 device_unregister(vib->dev); 203 ida_simple_remove(&minors, vib->minor); 204 gb_connection_disable(vib->connection); 205 gb_connection_destroy(vib->connection); 206 kfree(vib); 207 } 208 209 static const struct greybus_bundle_id gb_vibrator_id_table[] = { 210 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) }, 211 { } 212 }; 213 MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table); 214 215 static struct greybus_driver gb_vibrator_driver = { 216 .name = "vibrator", 217 .probe = gb_vibrator_probe, 218 .disconnect = gb_vibrator_disconnect, 219 .id_table = gb_vibrator_id_table, 220 }; 221 222 static __init int gb_vibrator_init(void) 223 { 224 int retval; 225 226 retval = class_register(&vibrator_class); 227 if (retval) 228 return retval; 229 230 retval = greybus_register(&gb_vibrator_driver); 231 if (retval) 232 goto err_class_unregister; 233 234 return 0; 235 236 err_class_unregister: 237 class_unregister(&vibrator_class); 238 239 return retval; 240 } 241 module_init(gb_vibrator_init); 242 243 static __exit void gb_vibrator_exit(void) 244 { 245 greybus_deregister(&gb_vibrator_driver); 246 class_unregister(&vibrator_class); 247 ida_destroy(&minors); 248 } 249 module_exit(gb_vibrator_exit); 250 251 MODULE_LICENSE("GPL v2"); 252