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