diff options
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a086ce8ed4eb..b2c5913ff72e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -122,6 +122,27 @@ enum { | |||
122 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | 122 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ |
123 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 | 123 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 |
124 | 124 | ||
125 | /* ACPI \WGSV commands */ | ||
126 | enum { | ||
127 | TP_ACPI_WGSV_GET_STATE = 0x01, /* Get state information */ | ||
128 | TP_ACPI_WGSV_PWR_ON_ON_RESUME = 0x02, /* Resume WWAN powered on */ | ||
129 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME = 0x03, /* Resume WWAN powered off */ | ||
130 | TP_ACPI_WGSV_SAVE_STATE = 0x04, /* Save state for S4/S5 */ | ||
131 | }; | ||
132 | |||
133 | /* TP_ACPI_WGSV_GET_STATE bits */ | ||
134 | enum { | ||
135 | TP_ACPI_WGSV_STATE_WWANEXIST = 0x0001, /* WWAN hw available */ | ||
136 | TP_ACPI_WGSV_STATE_WWANPWR = 0x0002, /* WWAN radio enabled */ | ||
137 | TP_ACPI_WGSV_STATE_WWANPWRRES = 0x0004, /* WWAN state at resume */ | ||
138 | TP_ACPI_WGSV_STATE_WWANBIOSOFF = 0x0008, /* WWAN disabled in BIOS */ | ||
139 | TP_ACPI_WGSV_STATE_BLTHEXIST = 0x0001, /* BLTH hw available */ | ||
140 | TP_ACPI_WGSV_STATE_BLTHPWR = 0x0002, /* BLTH radio enabled */ | ||
141 | TP_ACPI_WGSV_STATE_BLTHPWRRES = 0x0004, /* BLTH state at resume */ | ||
142 | TP_ACPI_WGSV_STATE_BLTHBIOSOFF = 0x0008, /* BLTH disabled in BIOS */ | ||
143 | TP_ACPI_WGSV_STATE_UWBEXIST = 0x0010, /* UWB hw available */ | ||
144 | TP_ACPI_WGSV_STATE_UWBPWR = 0x0020, /* UWB radio enabled */ | ||
145 | }; | ||
125 | 146 | ||
126 | /**************************************************************************** | 147 | /**************************************************************************** |
127 | * Main driver | 148 | * Main driver |
@@ -2766,11 +2787,28 @@ enum { | |||
2766 | /* ACPI GBDC/SBDC bits */ | 2787 | /* ACPI GBDC/SBDC bits */ |
2767 | TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ | 2788 | TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ |
2768 | TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ | 2789 | TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ |
2769 | TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ | 2790 | TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume: |
2791 | off / last state */ | ||
2792 | }; | ||
2793 | |||
2794 | enum { | ||
2795 | /* ACPI \BLTH commands */ | ||
2796 | TP_ACPI_BLTH_GET_ULTRAPORT_ID = 0x00, /* Get Ultraport BT ID */ | ||
2797 | TP_ACPI_BLTH_GET_PWR_ON_RESUME = 0x01, /* Get power-on-resume state */ | ||
2798 | TP_ACPI_BLTH_PWR_ON_ON_RESUME = 0x02, /* Resume powered on */ | ||
2799 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME = 0x03, /* Resume powered off */ | ||
2800 | TP_ACPI_BLTH_SAVE_STATE = 0x05, /* Save state for S4/S5 */ | ||
2770 | }; | 2801 | }; |
2771 | 2802 | ||
2772 | static struct rfkill *tpacpi_bluetooth_rfkill; | 2803 | static struct rfkill *tpacpi_bluetooth_rfkill; |
2773 | 2804 | ||
2805 | static void bluetooth_suspend(pm_message_t state) | ||
2806 | { | ||
2807 | /* Try to make sure radio will resume powered off */ | ||
2808 | acpi_evalf(NULL, NULL, "\\BLTH", "vd", | ||
2809 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME); | ||
2810 | } | ||
2811 | |||
2774 | static int bluetooth_get_radiosw(void) | 2812 | static int bluetooth_get_radiosw(void) |
2775 | { | 2813 | { |
2776 | int status; | 2814 | int status; |
@@ -2830,12 +2868,11 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk) | |||
2830 | } | 2868 | } |
2831 | #endif | 2869 | #endif |
2832 | 2870 | ||
2833 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2871 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ |
2834 | return -EIO; | ||
2835 | if (radio_on) | 2872 | if (radio_on) |
2836 | status |= TP_ACPI_BLUETOOTH_RADIOSSW; | 2873 | status = TP_ACPI_BLUETOOTH_RADIOSSW; |
2837 | else | 2874 | else |
2838 | status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; | 2875 | status = 0; |
2839 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 2876 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
2840 | return -EIO; | 2877 | return -EIO; |
2841 | 2878 | ||
@@ -3012,6 +3049,7 @@ static struct ibm_struct bluetooth_driver_data = { | |||
3012 | .read = bluetooth_read, | 3049 | .read = bluetooth_read, |
3013 | .write = bluetooth_write, | 3050 | .write = bluetooth_write, |
3014 | .exit = bluetooth_exit, | 3051 | .exit = bluetooth_exit, |
3052 | .suspend = bluetooth_suspend, | ||
3015 | }; | 3053 | }; |
3016 | 3054 | ||
3017 | /************************************************************************* | 3055 | /************************************************************************* |
@@ -3022,11 +3060,19 @@ enum { | |||
3022 | /* ACPI GWAN/SWAN bits */ | 3060 | /* ACPI GWAN/SWAN bits */ |
3023 | TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ | 3061 | TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ |
3024 | TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ | 3062 | TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ |
3025 | TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ | 3063 | TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume: |
3064 | off / last state */ | ||
3026 | }; | 3065 | }; |
3027 | 3066 | ||
3028 | static struct rfkill *tpacpi_wan_rfkill; | 3067 | static struct rfkill *tpacpi_wan_rfkill; |
3029 | 3068 | ||
3069 | static void wan_suspend(pm_message_t state) | ||
3070 | { | ||
3071 | /* Try to make sure radio will resume powered off */ | ||
3072 | acpi_evalf(NULL, NULL, "\\WGSV", "qvd", | ||
3073 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME); | ||
3074 | } | ||
3075 | |||
3030 | static int wan_get_radiosw(void) | 3076 | static int wan_get_radiosw(void) |
3031 | { | 3077 | { |
3032 | int status; | 3078 | int status; |
@@ -3086,12 +3132,11 @@ static int wan_set_radiosw(int radio_on, int update_rfk) | |||
3086 | } | 3132 | } |
3087 | #endif | 3133 | #endif |
3088 | 3134 | ||
3089 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 3135 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ |
3090 | return -EIO; | ||
3091 | if (radio_on) | 3136 | if (radio_on) |
3092 | status |= TP_ACPI_WANCARD_RADIOSSW; | 3137 | status = TP_ACPI_WANCARD_RADIOSSW; |
3093 | else | 3138 | else |
3094 | status &= ~TP_ACPI_WANCARD_RADIOSSW; | 3139 | status = 0; |
3095 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 3140 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
3096 | return -EIO; | 3141 | return -EIO; |
3097 | 3142 | ||
@@ -3266,6 +3311,7 @@ static struct ibm_struct wan_driver_data = { | |||
3266 | .read = wan_read, | 3311 | .read = wan_read, |
3267 | .write = wan_write, | 3312 | .write = wan_write, |
3268 | .exit = wan_exit, | 3313 | .exit = wan_exit, |
3314 | .suspend = wan_suspend, | ||
3269 | }; | 3315 | }; |
3270 | 3316 | ||
3271 | /************************************************************************* | 3317 | /************************************************************************* |