aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-01-11 00:01:03 -0500
committerLen Brown <len.brown@intel.com>2009-01-15 13:36:51 -0500
commit0045c0aa7d5e787f78938e6a10927b8a516f0b83 (patch)
tree48f2ac334391e800616fb6c4ae30a4d01db565cd /drivers/platform
parent90d9d3c79c44bcf95bc487e9bbceaff2de370310 (diff)
ACPI: thinkpad-acpi: add UWB radio support
Add rfkill support for USB UWB radio devices on very recent ThinkPad laptop models. The new subdriver is moslty a trimmed down copy of the wwan subdriver. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c206
1 files changed, 205 insertions, 1 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 27d709bac98f..c1d40410ad79 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -169,6 +169,7 @@ enum {
169enum { 169enum {
170 TPACPI_RFK_BLUETOOTH_SW_ID = 0, 170 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
171 TPACPI_RFK_WWAN_SW_ID, 171 TPACPI_RFK_WWAN_SW_ID,
172 TPACPI_RFK_UWB_SW_ID,
172}; 173};
173 174
174/* Debugging */ 175/* Debugging */
@@ -261,6 +262,7 @@ static struct {
261 u32 bright_16levels:1; 262 u32 bright_16levels:1;
262 u32 bright_acpimode:1; 263 u32 bright_acpimode:1;
263 u32 wan:1; 264 u32 wan:1;
265 u32 uwb:1;
264 u32 fan_ctrl_status_undef:1; 266 u32 fan_ctrl_status_undef:1;
265 u32 input_device_registered:1; 267 u32 input_device_registered:1;
266 u32 platform_drv_registered:1; 268 u32 platform_drv_registered:1;
@@ -317,6 +319,8 @@ static int dbg_bluetoothemul;
317static int tpacpi_bluetooth_emulstate; 319static int tpacpi_bluetooth_emulstate;
318static int dbg_wwanemul; 320static int dbg_wwanemul;
319static int tpacpi_wwan_emulstate; 321static int tpacpi_wwan_emulstate;
322static int dbg_uwbemul;
323static int tpacpi_uwb_emulstate;
320#endif 324#endif
321 325
322 326
@@ -967,6 +971,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
967 struct rfkill **rfk, 971 struct rfkill **rfk,
968 const enum rfkill_type rfktype, 972 const enum rfkill_type rfktype,
969 const char *name, 973 const char *name,
974 const bool set_default,
970 int (*toggle_radio)(void *, enum rfkill_state), 975 int (*toggle_radio)(void *, enum rfkill_state),
971 int (*get_state)(void *, enum rfkill_state *)) 976 int (*get_state)(void *, enum rfkill_state *))
972{ 977{
@@ -978,7 +983,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
978 printk(TPACPI_ERR 983 printk(TPACPI_ERR
979 "failed to read initial state for %s, error %d; " 984 "failed to read initial state for %s, error %d; "
980 "will turn radio off\n", name, res); 985 "will turn radio off\n", name, res);
981 } else { 986 } else if (set_default) {
982 /* try to set the initial state as the default for the rfkill 987 /* try to set the initial state as the default for the rfkill
983 * type, since we ask the firmware to preserve it across S5 in 988 * type, since we ask the firmware to preserve it across S5 in
984 * NVRAM */ 989 * NVRAM */
@@ -1148,6 +1153,31 @@ static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO,
1148 tpacpi_driver_wwan_emulstate_show, 1153 tpacpi_driver_wwan_emulstate_show,
1149 tpacpi_driver_wwan_emulstate_store); 1154 tpacpi_driver_wwan_emulstate_store);
1150 1155
1156/* uwb_emulstate ------------------------------------------------- */
1157static ssize_t tpacpi_driver_uwb_emulstate_show(
1158 struct device_driver *drv,
1159 char *buf)
1160{
1161 return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate);
1162}
1163
1164static ssize_t tpacpi_driver_uwb_emulstate_store(
1165 struct device_driver *drv,
1166 const char *buf, size_t count)
1167{
1168 unsigned long t;
1169
1170 if (parse_strtoul(buf, 1, &t))
1171 return -EINVAL;
1172
1173 tpacpi_uwb_emulstate = !!t;
1174
1175 return count;
1176}
1177
1178static DRIVER_ATTR(uwb_emulstate, S_IWUSR | S_IRUGO,
1179 tpacpi_driver_uwb_emulstate_show,
1180 tpacpi_driver_uwb_emulstate_store);
1151#endif 1181#endif
1152 1182
1153/* --------------------------------------------------------------------- */ 1183/* --------------------------------------------------------------------- */
@@ -1175,6 +1205,8 @@ static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
1175 res = driver_create_file(drv, &driver_attr_bluetooth_emulstate); 1205 res = driver_create_file(drv, &driver_attr_bluetooth_emulstate);
1176 if (!res && dbg_wwanemul) 1206 if (!res && dbg_wwanemul)
1177 res = driver_create_file(drv, &driver_attr_wwan_emulstate); 1207 res = driver_create_file(drv, &driver_attr_wwan_emulstate);
1208 if (!res && dbg_uwbemul)
1209 res = driver_create_file(drv, &driver_attr_uwb_emulstate);
1178#endif 1210#endif
1179 1211
1180 return res; 1212 return res;
@@ -1191,6 +1223,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
1191 driver_remove_file(drv, &driver_attr_wlsw_emulstate); 1223 driver_remove_file(drv, &driver_attr_wlsw_emulstate);
1192 driver_remove_file(drv, &driver_attr_bluetooth_emulstate); 1224 driver_remove_file(drv, &driver_attr_bluetooth_emulstate);
1193 driver_remove_file(drv, &driver_attr_wwan_emulstate); 1225 driver_remove_file(drv, &driver_attr_wwan_emulstate);
1226 driver_remove_file(drv, &driver_attr_uwb_emulstate);
1194#endif 1227#endif
1195} 1228}
1196 1229
@@ -2125,6 +2158,7 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
2125 2158
2126static void bluetooth_update_rfk(void); 2159static void bluetooth_update_rfk(void);
2127static void wan_update_rfk(void); 2160static void wan_update_rfk(void);
2161static void uwb_update_rfk(void);
2128static void tpacpi_send_radiosw_update(void) 2162static void tpacpi_send_radiosw_update(void)
2129{ 2163{
2130 int wlsw; 2164 int wlsw;
@@ -2134,6 +2168,8 @@ static void tpacpi_send_radiosw_update(void)
2134 bluetooth_update_rfk(); 2168 bluetooth_update_rfk();
2135 if (tp_features.wan) 2169 if (tp_features.wan)
2136 wan_update_rfk(); 2170 wan_update_rfk();
2171 if (tp_features.uwb)
2172 uwb_update_rfk();
2137 2173
2138 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { 2174 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
2139 mutex_lock(&tpacpi_inputdev_send_mutex); 2175 mutex_lock(&tpacpi_inputdev_send_mutex);
@@ -3035,6 +3071,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
3035 &tpacpi_bluetooth_rfkill, 3071 &tpacpi_bluetooth_rfkill,
3036 RFKILL_TYPE_BLUETOOTH, 3072 RFKILL_TYPE_BLUETOOTH,
3037 "tpacpi_bluetooth_sw", 3073 "tpacpi_bluetooth_sw",
3074 true,
3038 tpacpi_bluetooth_rfk_set, 3075 tpacpi_bluetooth_rfk_set,
3039 tpacpi_bluetooth_rfk_get); 3076 tpacpi_bluetooth_rfk_get);
3040 if (res) { 3077 if (res) {
@@ -3309,6 +3346,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
3309 &tpacpi_wan_rfkill, 3346 &tpacpi_wan_rfkill,
3310 RFKILL_TYPE_WWAN, 3347 RFKILL_TYPE_WWAN,
3311 "tpacpi_wwan_sw", 3348 "tpacpi_wwan_sw",
3349 true,
3312 tpacpi_wan_rfk_set, 3350 tpacpi_wan_rfk_set,
3313 tpacpi_wan_rfk_get); 3351 tpacpi_wan_rfk_get);
3314 if (res) { 3352 if (res) {
@@ -3366,6 +3404,162 @@ static struct ibm_struct wan_driver_data = {
3366}; 3404};
3367 3405
3368/************************************************************************* 3406/*************************************************************************
3407 * UWB subdriver
3408 */
3409
3410enum {
3411 /* ACPI GUWB/SUWB bits */
3412 TP_ACPI_UWB_HWPRESENT = 0x01, /* UWB hw available */
3413 TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */
3414};
3415
3416static struct rfkill *tpacpi_uwb_rfkill;
3417
3418static int uwb_get_radiosw(void)
3419{
3420 int status;
3421
3422 if (!tp_features.uwb)
3423 return -ENODEV;
3424
3425 /* WLSW overrides UWB in firmware/hardware, reflect that */
3426 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
3427 return RFKILL_STATE_HARD_BLOCKED;
3428
3429#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3430 if (dbg_uwbemul)
3431 return (tpacpi_uwb_emulstate) ?
3432 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
3433#endif
3434
3435 if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
3436 return -EIO;
3437
3438 return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
3439 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
3440}
3441
3442static void uwb_update_rfk(void)
3443{
3444 int status;
3445
3446 if (!tpacpi_uwb_rfkill)
3447 return;
3448
3449 status = uwb_get_radiosw();
3450 if (status < 0)
3451 return;
3452 rfkill_force_state(tpacpi_uwb_rfkill, status);
3453}
3454
3455static int uwb_set_radiosw(int radio_on, int update_rfk)
3456{
3457 int status;
3458
3459 if (!tp_features.uwb)
3460 return -ENODEV;
3461
3462 /* WLSW overrides UWB in firmware/hardware, but there is no
3463 * reason to risk weird behaviour. */
3464 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
3465 && radio_on)
3466 return -EPERM;
3467
3468#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3469 if (dbg_uwbemul) {
3470 tpacpi_uwb_emulstate = !!radio_on;
3471 if (update_rfk)
3472 uwb_update_rfk();
3473 return 0;
3474 }
3475#endif
3476
3477 status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0;
3478 if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
3479 return -EIO;
3480
3481 if (update_rfk)
3482 uwb_update_rfk();
3483
3484 return 0;
3485}
3486
3487/* --------------------------------------------------------------------- */
3488
3489static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
3490{
3491 int uwbs = uwb_get_radiosw();
3492
3493 if (uwbs < 0)
3494 return uwbs;
3495
3496 *state = uwbs;
3497 return 0;
3498}
3499
3500static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
3501{
3502 return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
3503}
3504
3505static void uwb_exit(void)
3506{
3507 if (tpacpi_uwb_rfkill)
3508 rfkill_unregister(tpacpi_uwb_rfkill);
3509}
3510
3511static int __init uwb_init(struct ibm_init_struct *iibm)
3512{
3513 int res;
3514 int status = 0;
3515
3516 vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n");
3517
3518 TPACPI_ACPIHANDLE_INIT(hkey);
3519
3520 tp_features.uwb = hkey_handle &&
3521 acpi_evalf(hkey_handle, &status, "GUWB", "qd");
3522
3523 vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n",
3524 str_supported(tp_features.uwb),
3525 status);
3526
3527#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3528 if (dbg_uwbemul) {
3529 tp_features.uwb = 1;
3530 printk(TPACPI_INFO
3531 "uwb switch emulation enabled\n");
3532 } else
3533#endif
3534 if (tp_features.uwb &&
3535 !(status & TP_ACPI_UWB_HWPRESENT)) {
3536 /* no uwb hardware present in system */
3537 tp_features.uwb = 0;
3538 dbg_printk(TPACPI_DBG_INIT,
3539 "uwb hardware not installed\n");
3540 }
3541
3542 if (!tp_features.uwb)
3543 return 1;
3544
3545 res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
3546 &tpacpi_uwb_rfkill,
3547 RFKILL_TYPE_UWB,
3548 "tpacpi_uwb_sw",
3549 false,
3550 tpacpi_uwb_rfk_set,
3551 tpacpi_uwb_rfk_get);
3552
3553 return res;
3554}
3555
3556static struct ibm_struct uwb_driver_data = {
3557 .name = "uwb",
3558 .exit = uwb_exit,
3559 .flags.experimental = 1,
3560};
3561
3562/*************************************************************************
3369 * Video subdriver 3563 * Video subdriver
3370 */ 3564 */
3371 3565
@@ -6830,6 +7024,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
6830 .init = wan_init, 7024 .init = wan_init,
6831 .data = &wan_driver_data, 7025 .data = &wan_driver_data,
6832 }, 7026 },
7027 {
7028 .init = uwb_init,
7029 .data = &uwb_driver_data,
7030 },
6833#ifdef CONFIG_THINKPAD_ACPI_VIDEO 7031#ifdef CONFIG_THINKPAD_ACPI_VIDEO
6834 { 7032 {
6835 .init = video_init, 7033 .init = video_init,
@@ -6986,6 +7184,12 @@ MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
6986module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); 7184module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
6987MODULE_PARM_DESC(wwan_state, 7185MODULE_PARM_DESC(wwan_state,
6988 "Initial state of the emulated WWAN switch"); 7186 "Initial state of the emulated WWAN switch");
7187
7188module_param(dbg_uwbemul, uint, 0);
7189MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
7190module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
7191MODULE_PARM_DESC(uwb_state,
7192 "Initial state of the emulated UWB switch");
6989#endif 7193#endif
6990 7194
6991static void thinkpad_acpi_module_exit(void) 7195static void thinkpad_acpi_module_exit(void)