diff options
author | Jiri Kosina <jkosina@suse.cz> | 2014-04-01 12:56:31 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-04-01 12:56:31 -0400 |
commit | ba04a57b4acd05a764471b2accd02000f6641881 (patch) | |
tree | 1d33fff219a72bb11a5a5d5f9c3dc2accfd19b06 /drivers/hid | |
parent | ee5f68e6c2f183e6aade0e9c57af13d5eff44f2f (diff) | |
parent | 34f439e4afcdf4bdb42fda62428535a843bca02d (diff) |
Merge branch 'for-3.15/i2c-hid' into for-linus
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index ce68a120ba26..c121990c6beb 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/pm.h> | 27 | #include <linux/pm.h> |
28 | #include <linux/pm_runtime.h> | ||
28 | #include <linux/device.h> | 29 | #include <linux/device.h> |
29 | #include <linux/wait.h> | 30 | #include <linux/wait.h> |
30 | #include <linux/err.h> | 31 | #include <linux/err.h> |
@@ -454,10 +455,18 @@ static void i2c_hid_init_reports(struct hid_device *hid) | |||
454 | return; | 455 | return; |
455 | } | 456 | } |
456 | 457 | ||
458 | /* | ||
459 | * The device must be powered on while we fetch initial reports | ||
460 | * from it. | ||
461 | */ | ||
462 | pm_runtime_get_sync(&client->dev); | ||
463 | |||
457 | list_for_each_entry(report, | 464 | list_for_each_entry(report, |
458 | &hid->report_enum[HID_FEATURE_REPORT].report_list, list) | 465 | &hid->report_enum[HID_FEATURE_REPORT].report_list, list) |
459 | i2c_hid_init_report(report, inbuf, ihid->bufsize); | 466 | i2c_hid_init_report(report, inbuf, ihid->bufsize); |
460 | 467 | ||
468 | pm_runtime_put(&client->dev); | ||
469 | |||
461 | kfree(inbuf); | 470 | kfree(inbuf); |
462 | } | 471 | } |
463 | 472 | ||
@@ -703,8 +712,8 @@ static int i2c_hid_open(struct hid_device *hid) | |||
703 | 712 | ||
704 | mutex_lock(&i2c_hid_open_mut); | 713 | mutex_lock(&i2c_hid_open_mut); |
705 | if (!hid->open++) { | 714 | if (!hid->open++) { |
706 | ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); | 715 | ret = pm_runtime_get_sync(&client->dev); |
707 | if (ret) { | 716 | if (ret < 0) { |
708 | hid->open--; | 717 | hid->open--; |
709 | goto done; | 718 | goto done; |
710 | } | 719 | } |
@@ -712,7 +721,7 @@ static int i2c_hid_open(struct hid_device *hid) | |||
712 | } | 721 | } |
713 | done: | 722 | done: |
714 | mutex_unlock(&i2c_hid_open_mut); | 723 | mutex_unlock(&i2c_hid_open_mut); |
715 | return ret; | 724 | return ret < 0 ? ret : 0; |
716 | } | 725 | } |
717 | 726 | ||
718 | static void i2c_hid_close(struct hid_device *hid) | 727 | static void i2c_hid_close(struct hid_device *hid) |
@@ -729,7 +738,7 @@ static void i2c_hid_close(struct hid_device *hid) | |||
729 | clear_bit(I2C_HID_STARTED, &ihid->flags); | 738 | clear_bit(I2C_HID_STARTED, &ihid->flags); |
730 | 739 | ||
731 | /* Save some power */ | 740 | /* Save some power */ |
732 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); | 741 | pm_runtime_put(&client->dev); |
733 | } | 742 | } |
734 | mutex_unlock(&i2c_hid_open_mut); | 743 | mutex_unlock(&i2c_hid_open_mut); |
735 | } | 744 | } |
@@ -738,19 +747,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl) | |||
738 | { | 747 | { |
739 | struct i2c_client *client = hid->driver_data; | 748 | struct i2c_client *client = hid->driver_data; |
740 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 749 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
741 | int ret = 0; | ||
742 | 750 | ||
743 | i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); | 751 | i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); |
744 | 752 | ||
745 | switch (lvl) { | 753 | switch (lvl) { |
746 | case PM_HINT_FULLON: | 754 | case PM_HINT_FULLON: |
747 | ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); | 755 | pm_runtime_get_sync(&client->dev); |
748 | break; | 756 | break; |
749 | case PM_HINT_NORMAL: | 757 | case PM_HINT_NORMAL: |
750 | ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); | 758 | pm_runtime_put(&client->dev); |
751 | break; | 759 | break; |
752 | } | 760 | } |
753 | return ret; | 761 | return 0; |
754 | } | 762 | } |
755 | 763 | ||
756 | static struct hid_ll_driver i2c_hid_ll_driver = { | 764 | static struct hid_ll_driver i2c_hid_ll_driver = { |
@@ -987,13 +995,17 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
987 | if (ret < 0) | 995 | if (ret < 0) |
988 | goto err; | 996 | goto err; |
989 | 997 | ||
998 | pm_runtime_get_noresume(&client->dev); | ||
999 | pm_runtime_set_active(&client->dev); | ||
1000 | pm_runtime_enable(&client->dev); | ||
1001 | |||
990 | ret = i2c_hid_fetch_hid_descriptor(ihid); | 1002 | ret = i2c_hid_fetch_hid_descriptor(ihid); |
991 | if (ret < 0) | 1003 | if (ret < 0) |
992 | goto err; | 1004 | goto err_pm; |
993 | 1005 | ||
994 | ret = i2c_hid_init_irq(client); | 1006 | ret = i2c_hid_init_irq(client); |
995 | if (ret < 0) | 1007 | if (ret < 0) |
996 | goto err; | 1008 | goto err_pm; |
997 | 1009 | ||
998 | hid = hid_allocate_device(); | 1010 | hid = hid_allocate_device(); |
999 | if (IS_ERR(hid)) { | 1011 | if (IS_ERR(hid)) { |
@@ -1024,6 +1036,7 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
1024 | goto err_mem_free; | 1036 | goto err_mem_free; |
1025 | } | 1037 | } |
1026 | 1038 | ||
1039 | pm_runtime_put(&client->dev); | ||
1027 | return 0; | 1040 | return 0; |
1028 | 1041 | ||
1029 | err_mem_free: | 1042 | err_mem_free: |
@@ -1032,6 +1045,10 @@ err_mem_free: | |||
1032 | err_irq: | 1045 | err_irq: |
1033 | free_irq(client->irq, ihid); | 1046 | free_irq(client->irq, ihid); |
1034 | 1047 | ||
1048 | err_pm: | ||
1049 | pm_runtime_put_noidle(&client->dev); | ||
1050 | pm_runtime_disable(&client->dev); | ||
1051 | |||
1035 | err: | 1052 | err: |
1036 | i2c_hid_free_buffers(ihid); | 1053 | i2c_hid_free_buffers(ihid); |
1037 | kfree(ihid); | 1054 | kfree(ihid); |
@@ -1043,6 +1060,11 @@ static int i2c_hid_remove(struct i2c_client *client) | |||
1043 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 1060 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
1044 | struct hid_device *hid; | 1061 | struct hid_device *hid; |
1045 | 1062 | ||
1063 | pm_runtime_get_sync(&client->dev); | ||
1064 | pm_runtime_disable(&client->dev); | ||
1065 | pm_runtime_set_suspended(&client->dev); | ||
1066 | pm_runtime_put_noidle(&client->dev); | ||
1067 | |||
1046 | hid = ihid->hid; | 1068 | hid = ihid->hid; |
1047 | hid_destroy_device(hid); | 1069 | hid_destroy_device(hid); |
1048 | 1070 | ||
@@ -1088,7 +1110,31 @@ static int i2c_hid_resume(struct device *dev) | |||
1088 | } | 1110 | } |
1089 | #endif | 1111 | #endif |
1090 | 1112 | ||
1091 | static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume); | 1113 | #ifdef CONFIG_PM_RUNTIME |
1114 | static int i2c_hid_runtime_suspend(struct device *dev) | ||
1115 | { | ||
1116 | struct i2c_client *client = to_i2c_client(dev); | ||
1117 | |||
1118 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); | ||
1119 | disable_irq(client->irq); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int i2c_hid_runtime_resume(struct device *dev) | ||
1124 | { | ||
1125 | struct i2c_client *client = to_i2c_client(dev); | ||
1126 | |||
1127 | enable_irq(client->irq); | ||
1128 | i2c_hid_set_power(client, I2C_HID_PWR_ON); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | #endif | ||
1132 | |||
1133 | static const struct dev_pm_ops i2c_hid_pm = { | ||
1134 | SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume) | ||
1135 | SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume, | ||
1136 | NULL) | ||
1137 | }; | ||
1092 | 1138 | ||
1093 | static const struct i2c_device_id i2c_hid_id_table[] = { | 1139 | static const struct i2c_device_id i2c_hid_id_table[] = { |
1094 | { "hid", 0 }, | 1140 | { "hid", 0 }, |