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

i2c-hid-of.c (4025B)


      1/*
      2 * HID over I2C Open Firmware Subclass
      3 *
      4 * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
      5 * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France
      6 * Copyright (c) 2012 Red Hat, Inc
      7 *
      8 * This code was forked out of the core code, which was partly based on
      9 * "USB HID support for Linux":
     10 *
     11 *  Copyright (c) 1999 Andreas Gal
     12 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
     13 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
     14 *  Copyright (c) 2007-2008 Oliver Neukum
     15 *  Copyright (c) 2006-2010 Jiri Kosina
     16 *
     17 * This file is subject to the terms and conditions of the GNU General Public
     18 * License.  See the file COPYING in the main directory of this archive for
     19 * more details.
     20 */
     21
     22#include <linux/delay.h>
     23#include <linux/device.h>
     24#include <linux/hid.h>
     25#include <linux/i2c.h>
     26#include <linux/kernel.h>
     27#include <linux/module.h>
     28#include <linux/of.h>
     29#include <linux/pm.h>
     30#include <linux/regulator/consumer.h>
     31
     32#include "i2c-hid.h"
     33
     34struct i2c_hid_of {
     35	struct i2chid_ops ops;
     36
     37	struct i2c_client *client;
     38	struct regulator_bulk_data supplies[2];
     39	int post_power_delay_ms;
     40};
     41
     42static int i2c_hid_of_power_up(struct i2chid_ops *ops)
     43{
     44	struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
     45	struct device *dev = &ihid_of->client->dev;
     46	int ret;
     47
     48	ret = regulator_bulk_enable(ARRAY_SIZE(ihid_of->supplies),
     49				    ihid_of->supplies);
     50	if (ret) {
     51		dev_warn(dev, "Failed to enable supplies: %d\n", ret);
     52		return ret;
     53	}
     54
     55	if (ihid_of->post_power_delay_ms)
     56		msleep(ihid_of->post_power_delay_ms);
     57
     58	return 0;
     59}
     60
     61static void i2c_hid_of_power_down(struct i2chid_ops *ops)
     62{
     63	struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
     64
     65	regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies),
     66			       ihid_of->supplies);
     67}
     68
     69static int i2c_hid_of_probe(struct i2c_client *client,
     70			    const struct i2c_device_id *dev_id)
     71{
     72	struct device *dev = &client->dev;
     73	struct i2c_hid_of *ihid_of;
     74	u16 hid_descriptor_address;
     75	u32 quirks = 0;
     76	int ret;
     77	u32 val;
     78
     79	ihid_of = devm_kzalloc(&client->dev, sizeof(*ihid_of), GFP_KERNEL);
     80	if (!ihid_of)
     81		return -ENOMEM;
     82
     83	ihid_of->ops.power_up = i2c_hid_of_power_up;
     84	ihid_of->ops.power_down = i2c_hid_of_power_down;
     85
     86	ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
     87	if (ret) {
     88		dev_err(&client->dev, "HID register address not provided\n");
     89		return -ENODEV;
     90	}
     91	if (val >> 16) {
     92		dev_err(&client->dev, "Bad HID register address: 0x%08x\n",
     93			val);
     94		return -EINVAL;
     95	}
     96	hid_descriptor_address = val;
     97
     98	if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms",
     99				      &val))
    100		ihid_of->post_power_delay_ms = val;
    101
    102	ihid_of->supplies[0].supply = "vdd";
    103	ihid_of->supplies[1].supply = "vddl";
    104	ret = devm_regulator_bulk_get(&client->dev,
    105				      ARRAY_SIZE(ihid_of->supplies),
    106				      ihid_of->supplies);
    107	if (ret)
    108		return ret;
    109
    110	if (device_property_read_bool(dev, "touchscreen-inverted-x"))
    111		quirks |= HID_QUIRK_X_INVERT;
    112
    113	if (device_property_read_bool(dev, "touchscreen-inverted-y"))
    114		quirks |= HID_QUIRK_Y_INVERT;
    115
    116	return i2c_hid_core_probe(client, &ihid_of->ops,
    117				  hid_descriptor_address, quirks);
    118}
    119
    120static const struct of_device_id i2c_hid_of_match[] = {
    121	{ .compatible = "hid-over-i2c" },
    122	{},
    123};
    124MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
    125
    126static const struct i2c_device_id i2c_hid_of_id_table[] = {
    127	{ "hid", 0 },
    128	{ "hid-over-i2c", 0 },
    129	{ },
    130};
    131MODULE_DEVICE_TABLE(i2c, i2c_hid_of_id_table);
    132
    133static struct i2c_driver i2c_hid_of_driver = {
    134	.driver = {
    135		.name	= "i2c_hid_of",
    136		.pm	= &i2c_hid_core_pm,
    137		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    138		.of_match_table = of_match_ptr(i2c_hid_of_match),
    139	},
    140
    141	.probe		= i2c_hid_of_probe,
    142	.remove		= i2c_hid_core_remove,
    143	.shutdown	= i2c_hid_core_shutdown,
    144	.id_table	= i2c_hid_of_id_table,
    145};
    146
    147module_i2c_driver(i2c_hid_of_driver);
    148
    149MODULE_DESCRIPTION("HID over I2C OF driver");
    150MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
    151MODULE_LICENSE("GPL");