Skip to content

Commit acf7f4a

Browse files
mrhpearsonandy-shev
authored andcommitted
platform/x86: thinkpad_acpi: lap or desk mode interface
Newer Lenovo Thinkpad platforms have support to identify whether the system is on-lap or not using an ACPI DYTC event from the firmware. This patch provides the ability to retrieve the current mode via sysfs entrypoints and will be used by userspace for thermal mode and WWAN functionality Co-developed-by: Nitin Joshi <njoshi1@lenovo.com> Signed-off-by: Nitin Joshi <njoshi1@lenovo.com> Reviewed-by: Sugumaran <slacshiminar@lenovo.com> Reviewed-by: Bastien Nocera <bnocera@redhat.com> Signed-off-by: Mark Pearson <markpearson@lenovo.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
1 parent df11f6c commit acf7f4a

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

Documentation/admin-guide/laptops/thinkpad-acpi.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ detailed description):
5050
- WAN enable and disable
5151
- UWB enable and disable
5252
- LCD Shadow (PrivacyGuard) enable and disable
53+
- Lap mode sensor
5354

5455
A compatibility table by model and feature is maintained on the web
5556
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -1432,6 +1433,20 @@ The first command ensures the best viewing angle and the latter one turns
14321433
on the feature, restricting the viewing angles.
14331434

14341435

1436+
DYTC Lapmode sensor
1437+
------------------
1438+
1439+
sysfs: dytc_lapmode
1440+
1441+
Newer thinkpads and mobile workstations have the ability to determine if
1442+
the device is in deskmode or lapmode. This feature is used by user space
1443+
to decide if WWAN transmission can be increased to maximum power and is
1444+
also useful for understanding the different thermal modes available as
1445+
they differ between desk and lap mode.
1446+
1447+
The property is read-only. If the platform doesn't have support the sysfs
1448+
class is not created.
1449+
14351450
EXPERIMENTAL: UWB
14361451
-----------------
14371452

drivers/platform/x86/thinkpad_acpi.c

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,8 +4030,8 @@ static bool hotkey_notify_6xxx(const u32 hkey,
40304030
return true;
40314031
case TP_HKEY_EV_THM_CSM_COMPLETED:
40324032
pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n");
4033-
/* recommended action: do nothing, we don't have
4034-
* Lenovo ATM information */
4033+
/* Thermal event - pass on to event handler */
4034+
tpacpi_driver_event(hkey);
40354035
return true;
40364036
case TP_HKEY_EV_THM_TRANSFM_CHANGED:
40374037
pr_debug("EC reports: Thermal Transformation changed (GMTS)\n");
@@ -9803,6 +9803,105 @@ static struct ibm_struct lcdshadow_driver_data = {
98039803
.write = lcdshadow_write,
98049804
};
98059805

9806+
/*************************************************************************
9807+
* DYTC subdriver, for the Lenovo lapmode feature
9808+
*/
9809+
9810+
#define DYTC_CMD_GET 2 /* To get current IC function and mode */
9811+
#define DYTC_GET_LAPMODE_BIT 17 /* Set when in lapmode */
9812+
9813+
static bool dytc_lapmode;
9814+
9815+
static void dytc_lapmode_notify_change(void)
9816+
{
9817+
sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "dytc_lapmode");
9818+
}
9819+
9820+
static int dytc_command(int command, int *output)
9821+
{
9822+
acpi_handle dytc_handle;
9823+
9824+
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DYTC", &dytc_handle))) {
9825+
/* Platform doesn't support DYTC */
9826+
return -ENODEV;
9827+
}
9828+
if (!acpi_evalf(dytc_handle, output, NULL, "dd", command))
9829+
return -EIO;
9830+
return 0;
9831+
}
9832+
9833+
static int dytc_lapmode_get(bool *state)
9834+
{
9835+
int output, err;
9836+
9837+
err = dytc_command(DYTC_CMD_GET, &output);
9838+
if (err)
9839+
return err;
9840+
*state = output & BIT(DYTC_GET_LAPMODE_BIT) ? true : false;
9841+
return 0;
9842+
}
9843+
9844+
static void dytc_lapmode_refresh(void)
9845+
{
9846+
bool new_state;
9847+
int err;
9848+
9849+
err = dytc_lapmode_get(&new_state);
9850+
if (err || (new_state == dytc_lapmode))
9851+
return;
9852+
9853+
dytc_lapmode = new_state;
9854+
dytc_lapmode_notify_change();
9855+
}
9856+
9857+
/* sysfs lapmode entry */
9858+
static ssize_t dytc_lapmode_show(struct device *dev,
9859+
struct device_attribute *attr,
9860+
char *buf)
9861+
{
9862+
return snprintf(buf, PAGE_SIZE, "%d\n", dytc_lapmode);
9863+
}
9864+
9865+
static DEVICE_ATTR_RO(dytc_lapmode);
9866+
9867+
static struct attribute *dytc_attributes[] = {
9868+
&dev_attr_dytc_lapmode.attr,
9869+
NULL,
9870+
};
9871+
9872+
static const struct attribute_group dytc_attr_group = {
9873+
.attrs = dytc_attributes,
9874+
};
9875+
9876+
static int tpacpi_dytc_init(struct ibm_init_struct *iibm)
9877+
{
9878+
int err;
9879+
9880+
err = dytc_lapmode_get(&dytc_lapmode);
9881+
/* If support isn't available (ENODEV) then don't return an error
9882+
* but just don't create the sysfs group
9883+
*/
9884+
if (err == -ENODEV)
9885+
return 0;
9886+
/* For all other errors we can flag the failure */
9887+
if (err)
9888+
return err;
9889+
9890+
/* Platform supports this feature - create the group */
9891+
err = sysfs_create_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
9892+
return err;
9893+
}
9894+
9895+
static void dytc_exit(void)
9896+
{
9897+
sysfs_remove_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
9898+
}
9899+
9900+
static struct ibm_struct dytc_driver_data = {
9901+
.name = "dytc",
9902+
.exit = dytc_exit,
9903+
};
9904+
98069905
/****************************************************************************
98079906
****************************************************************************
98089907
*
@@ -9850,6 +9949,10 @@ static void tpacpi_driver_event(const unsigned int hkey_event)
98509949

98519950
mutex_unlock(&kbdlight_mutex);
98529951
}
9952+
9953+
if (hkey_event == TP_HKEY_EV_THM_CSM_COMPLETED)
9954+
dytc_lapmode_refresh();
9955+
98539956
}
98549957

98559958
static void hotkey_driver_event(const unsigned int scancode)
@@ -10288,6 +10391,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
1028810391
.init = tpacpi_lcdshadow_init,
1028910392
.data = &lcdshadow_driver_data,
1029010393
},
10394+
{
10395+
.init = tpacpi_dytc_init,
10396+
.data = &dytc_driver_data,
10397+
},
1029110398
};
1029210399

1029310400
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)

0 commit comments

Comments
 (0)