root/drivers/staging/greybus/vibrator.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. turn_off
  2. turn_on
  3. gb_vibrator_worker
  4. timeout_store
  5. gb_vibrator_probe
  6. gb_vibrator_disconnect
  7. gb_vibrator_init
  8. gb_vibrator_exit

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

/* [<][>][^][v][top][bottom][index][help] */