linux/drivers/staging/greybus/vibrator.c
<<
>>
Prefs
   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
  20struct 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
  31static 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
  44static 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
  69static 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
  80static 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}
 102static DEVICE_ATTR_WO(timeout);
 103
 104static struct attribute *vibrator_attrs[] = {
 105        &dev_attr_timeout.attr,
 106        NULL,
 107};
 108ATTRIBUTE_GROUPS(vibrator);
 109
 110static struct class vibrator_class = {
 111        .name           = "vibrator",
 112        .owner          = THIS_MODULE,
 113        .dev_groups     = vibrator_groups,
 114};
 115
 116static DEFINE_IDA(minors);
 117
 118static 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
 178err_ida_remove:
 179        ida_simple_remove(&minors, vib->minor);
 180err_connection_disable:
 181        gb_connection_disable(connection);
 182err_connection_destroy:
 183        gb_connection_destroy(connection);
 184err_free_vib:
 185        kfree(vib);
 186
 187        return retval;
 188}
 189
 190static 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
 209static const struct greybus_bundle_id gb_vibrator_id_table[] = {
 210        { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
 211        { }
 212};
 213MODULE_DEVICE_TABLE(greybus, gb_vibrator_id_table);
 214
 215static 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
 222static __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
 236err_class_unregister:
 237        class_unregister(&vibrator_class);
 238
 239        return retval;
 240}
 241module_init(gb_vibrator_init);
 242
 243static __exit void gb_vibrator_exit(void)
 244{
 245        greybus_deregister(&gb_vibrator_driver);
 246        class_unregister(&vibrator_class);
 247        ida_destroy(&minors);
 248}
 249module_exit(gb_vibrator_exit);
 250
 251MODULE_LICENSE("GPL v2");
 252