cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vibrator.c (5549B)


      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");