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