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