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