diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2015-02-23 08:52:45 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-02-24 14:53:30 -0500 |
commit | a485923efbb83056b7fb79e4fd2fee05c990ad5e (patch) | |
tree | 33ad6cb9a02e639f75cc999c53a649c5e5b1cd2f /drivers/hid | |
parent | c4bbb39806cf4098d7a01a779b40171047004046 (diff) |
HID: i2c-hid: Add support for ACPI GPIO interrupts
The HID over I2C specification allows to have the interrupt for a HID
device to be GPIO instead of directly connected to the IO-APIC.
Add support for this so that when the driver does not find proper interrupt
number from the I2C client structure we check if it has ACPI GpioInt()
resource listed in _CRS. If it is found we convert it to an interrupt
number and use it instead.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 68 |
1 files changed, 50 insertions, 18 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 36053f33d6d9..ab4dd952b6ba 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
38 | #include <linux/acpi.h> | 38 | #include <linux/acpi.h> |
39 | #include <linux/of.h> | 39 | #include <linux/of.h> |
40 | #include <linux/gpio/consumer.h> | ||
40 | 41 | ||
41 | #include <linux/i2c/i2c-hid.h> | 42 | #include <linux/i2c/i2c-hid.h> |
42 | 43 | ||
@@ -144,6 +145,8 @@ struct i2c_hid { | |||
144 | unsigned long flags; /* device flags */ | 145 | unsigned long flags; /* device flags */ |
145 | 146 | ||
146 | wait_queue_head_t wait; /* For waiting the interrupt */ | 147 | wait_queue_head_t wait; /* For waiting the interrupt */ |
148 | struct gpio_desc *desc; | ||
149 | int irq; | ||
147 | 150 | ||
148 | struct i2c_hid_platform_data pdata; | 151 | struct i2c_hid_platform_data pdata; |
149 | }; | 152 | }; |
@@ -785,16 +788,16 @@ static int i2c_hid_init_irq(struct i2c_client *client) | |||
785 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 788 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
786 | int ret; | 789 | int ret; |
787 | 790 | ||
788 | dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq); | 791 | dev_dbg(&client->dev, "Requesting IRQ: %d\n", ihid->irq); |
789 | 792 | ||
790 | ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq, | 793 | ret = request_threaded_irq(ihid->irq, NULL, i2c_hid_irq, |
791 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 794 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
792 | client->name, ihid); | 795 | client->name, ihid); |
793 | if (ret < 0) { | 796 | if (ret < 0) { |
794 | dev_warn(&client->dev, | 797 | dev_warn(&client->dev, |
795 | "Could not register for %s interrupt, irq = %d," | 798 | "Could not register for %s interrupt, irq = %d," |
796 | " ret = %d\n", | 799 | " ret = %d\n", |
797 | client->name, client->irq, ret); | 800 | client->name, ihid->irq, ret); |
798 | 801 | ||
799 | return ret; | 802 | return ret; |
800 | } | 803 | } |
@@ -841,6 +844,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) | |||
841 | } | 844 | } |
842 | 845 | ||
843 | #ifdef CONFIG_ACPI | 846 | #ifdef CONFIG_ACPI |
847 | |||
848 | /* Default GPIO mapping */ | ||
849 | static const struct acpi_gpio_params i2c_hid_irq_gpio = { 0, 0, true }; | ||
850 | static const struct acpi_gpio_mapping i2c_hid_acpi_gpios[] = { | ||
851 | { "gpios", &i2c_hid_irq_gpio, 1 }, | ||
852 | { }, | ||
853 | }; | ||
854 | |||
844 | static int i2c_hid_acpi_pdata(struct i2c_client *client, | 855 | static int i2c_hid_acpi_pdata(struct i2c_client *client, |
845 | struct i2c_hid_platform_data *pdata) | 856 | struct i2c_hid_platform_data *pdata) |
846 | { | 857 | { |
@@ -866,7 +877,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, | |||
866 | pdata->hid_descriptor_address = obj->integer.value; | 877 | pdata->hid_descriptor_address = obj->integer.value; |
867 | ACPI_FREE(obj); | 878 | ACPI_FREE(obj); |
868 | 879 | ||
869 | return 0; | 880 | return acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios); |
870 | } | 881 | } |
871 | 882 | ||
872 | static const struct acpi_device_id i2c_hid_acpi_match[] = { | 883 | static const struct acpi_device_id i2c_hid_acpi_match[] = { |
@@ -930,12 +941,6 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
930 | 941 | ||
931 | dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); | 942 | dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); |
932 | 943 | ||
933 | if (!client->irq) { | ||
934 | dev_err(&client->dev, | ||
935 | "HID over i2c has not been provided an Int IRQ\n"); | ||
936 | return -EINVAL; | ||
937 | } | ||
938 | |||
939 | ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); | 944 | ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); |
940 | if (!ihid) | 945 | if (!ihid) |
941 | return -ENOMEM; | 946 | return -ENOMEM; |
@@ -955,6 +960,23 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
955 | ihid->pdata = *platform_data; | 960 | ihid->pdata = *platform_data; |
956 | } | 961 | } |
957 | 962 | ||
963 | if (client->irq > 0) { | ||
964 | ihid->irq = client->irq; | ||
965 | } else if (ACPI_COMPANION(&client->dev)) { | ||
966 | ihid->desc = gpiod_get(&client->dev, NULL, GPIOD_IN); | ||
967 | if (IS_ERR(ihid->desc)) { | ||
968 | dev_err(&client->dev, "Failed to get GPIO interrupt\n"); | ||
969 | return PTR_ERR(ihid->desc); | ||
970 | } | ||
971 | |||
972 | ihid->irq = gpiod_to_irq(ihid->desc); | ||
973 | if (ihid->irq < 0) { | ||
974 | gpiod_put(ihid->desc); | ||
975 | dev_err(&client->dev, "Failed to convert GPIO to IRQ\n"); | ||
976 | return ihid->irq; | ||
977 | } | ||
978 | } | ||
979 | |||
958 | i2c_set_clientdata(client, ihid); | 980 | i2c_set_clientdata(client, ihid); |
959 | 981 | ||
960 | ihid->client = client; | 982 | ihid->client = client; |
@@ -1017,13 +1039,16 @@ err_mem_free: | |||
1017 | hid_destroy_device(hid); | 1039 | hid_destroy_device(hid); |
1018 | 1040 | ||
1019 | err_irq: | 1041 | err_irq: |
1020 | free_irq(client->irq, ihid); | 1042 | free_irq(ihid->irq, ihid); |
1021 | 1043 | ||
1022 | err_pm: | 1044 | err_pm: |
1023 | pm_runtime_put_noidle(&client->dev); | 1045 | pm_runtime_put_noidle(&client->dev); |
1024 | pm_runtime_disable(&client->dev); | 1046 | pm_runtime_disable(&client->dev); |
1025 | 1047 | ||
1026 | err: | 1048 | err: |
1049 | if (ihid->desc) | ||
1050 | gpiod_put(ihid->desc); | ||
1051 | |||
1027 | i2c_hid_free_buffers(ihid); | 1052 | i2c_hid_free_buffers(ihid); |
1028 | kfree(ihid); | 1053 | kfree(ihid); |
1029 | return ret; | 1054 | return ret; |
@@ -1042,13 +1067,18 @@ static int i2c_hid_remove(struct i2c_client *client) | |||
1042 | hid = ihid->hid; | 1067 | hid = ihid->hid; |
1043 | hid_destroy_device(hid); | 1068 | hid_destroy_device(hid); |
1044 | 1069 | ||
1045 | free_irq(client->irq, ihid); | 1070 | free_irq(ihid->irq, ihid); |
1046 | 1071 | ||
1047 | if (ihid->bufsize) | 1072 | if (ihid->bufsize) |
1048 | i2c_hid_free_buffers(ihid); | 1073 | i2c_hid_free_buffers(ihid); |
1049 | 1074 | ||
1075 | if (ihid->desc) | ||
1076 | gpiod_put(ihid->desc); | ||
1077 | |||
1050 | kfree(ihid); | 1078 | kfree(ihid); |
1051 | 1079 | ||
1080 | acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); | ||
1081 | |||
1052 | return 0; | 1082 | return 0; |
1053 | } | 1083 | } |
1054 | 1084 | ||
@@ -1060,9 +1090,9 @@ static int i2c_hid_suspend(struct device *dev) | |||
1060 | struct hid_device *hid = ihid->hid; | 1090 | struct hid_device *hid = ihid->hid; |
1061 | int ret = 0; | 1091 | int ret = 0; |
1062 | 1092 | ||
1063 | disable_irq(client->irq); | 1093 | disable_irq(ihid->irq); |
1064 | if (device_may_wakeup(&client->dev)) | 1094 | if (device_may_wakeup(&client->dev)) |
1065 | enable_irq_wake(client->irq); | 1095 | enable_irq_wake(ihid->irq); |
1066 | 1096 | ||
1067 | if (hid->driver && hid->driver->suspend) | 1097 | if (hid->driver && hid->driver->suspend) |
1068 | ret = hid->driver->suspend(hid, PMSG_SUSPEND); | 1098 | ret = hid->driver->suspend(hid, PMSG_SUSPEND); |
@@ -1080,13 +1110,13 @@ static int i2c_hid_resume(struct device *dev) | |||
1080 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 1110 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
1081 | struct hid_device *hid = ihid->hid; | 1111 | struct hid_device *hid = ihid->hid; |
1082 | 1112 | ||
1083 | enable_irq(client->irq); | 1113 | enable_irq(ihid->irq); |
1084 | ret = i2c_hid_hwreset(client); | 1114 | ret = i2c_hid_hwreset(client); |
1085 | if (ret) | 1115 | if (ret) |
1086 | return ret; | 1116 | return ret; |
1087 | 1117 | ||
1088 | if (device_may_wakeup(&client->dev)) | 1118 | if (device_may_wakeup(&client->dev)) |
1089 | disable_irq_wake(client->irq); | 1119 | disable_irq_wake(ihid->irq); |
1090 | 1120 | ||
1091 | if (hid->driver && hid->driver->reset_resume) { | 1121 | if (hid->driver && hid->driver->reset_resume) { |
1092 | ret = hid->driver->reset_resume(hid); | 1122 | ret = hid->driver->reset_resume(hid); |
@@ -1101,17 +1131,19 @@ static int i2c_hid_resume(struct device *dev) | |||
1101 | static int i2c_hid_runtime_suspend(struct device *dev) | 1131 | static int i2c_hid_runtime_suspend(struct device *dev) |
1102 | { | 1132 | { |
1103 | struct i2c_client *client = to_i2c_client(dev); | 1133 | struct i2c_client *client = to_i2c_client(dev); |
1134 | struct i2c_hid *ihid = i2c_get_clientdata(client); | ||
1104 | 1135 | ||
1105 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); | 1136 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); |
1106 | disable_irq(client->irq); | 1137 | disable_irq(ihid->irq); |
1107 | return 0; | 1138 | return 0; |
1108 | } | 1139 | } |
1109 | 1140 | ||
1110 | static int i2c_hid_runtime_resume(struct device *dev) | 1141 | static int i2c_hid_runtime_resume(struct device *dev) |
1111 | { | 1142 | { |
1112 | struct i2c_client *client = to_i2c_client(dev); | 1143 | struct i2c_client *client = to_i2c_client(dev); |
1144 | struct i2c_hid *ihid = i2c_get_clientdata(client); | ||
1113 | 1145 | ||
1114 | enable_irq(client->irq); | 1146 | enable_irq(ihid->irq); |
1115 | i2c_hid_set_power(client, I2C_HID_PWR_ON); | 1147 | i2c_hid_set_power(client, I2C_HID_PWR_ON); |
1116 | return 0; | 1148 | return 0; |
1117 | } | 1149 | } |