Commit 3feb52a2 authored by Nitin Joshi's avatar Nitin Joshi Committed by Hans de Goede

platform/x86: thinkpad_acpi: sysfs interface to get wwan antenna type

On some newer Thinkpads we need to set SAR value based on antenna type.
This patch provides a sysfs interface that userspace can use to get
antenna type and set corresponding SAR value, as is required for FCC
certification.
Reviewed-by: default avatarMark Pearson <markpearson@lenovo.com>
Signed-off-by: default avatarNitin Joshi <njoshi1@lenovo.com>
Link: https://lore.kernel.org/r/20210317024636.356175-1-njoshi1@lenovo.comSigned-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 2728f39d
......@@ -52,6 +52,7 @@ detailed description):
- LCD Shadow (PrivacyGuard) enable and disable
- Lap mode sensor
- Setting keyboard language
- WWAN Antenna type
A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
......@@ -1490,6 +1491,25 @@ fr(French), fr-ch(French(Switzerland)), hu(Hungarian), it(Italy), jp (Japan),
nl(Dutch), nn(Norway), pl(Polish), pt(portugese), sl(Slovenian), sv(Sweden),
tr(Turkey)
WWAN Antenna type
-----------------
sysfs: wwan_antenna_type
On some newer Thinkpads we need to set SAR value based on the antenna
type. This interface will be used by userspace to get the antenna type
and set the corresponding SAR value, as is required for FCC certification.
The available commands are::
cat /sys/devices/platform/thinkpad_acpi/wwan_antenna_type
Currently 2 antenna types are supported as mentioned below:
- type a
- type b
The property is read-only. If the platform doesn't have support the sysfs
class is not created.
Adaptive keyboard
-----------------
......
......@@ -10496,6 +10496,111 @@ static struct ibm_struct kbdlang_driver_data = {
.exit = kbdlang_exit,
};
/*************************************************************************
* DPRC(Dynamic Power Reduction Control) subdriver, for the Lenovo WWAN
* and WLAN feature.
*/
#define DPRC_GET_WWAN_ANTENNA_TYPE 0x40000
#define DPRC_WWAN_ANTENNA_TYPE_A_BIT BIT(4)
#define DPRC_WWAN_ANTENNA_TYPE_B_BIT BIT(8)
static bool has_antennatype;
static int wwan_antennatype;
static int dprc_command(int command, int *output)
{
acpi_handle dprc_handle;
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DPRC", &dprc_handle))) {
/* Platform doesn't support DPRC */
return -ENODEV;
}
if (!acpi_evalf(dprc_handle, output, NULL, "dd", command))
return -EIO;
/*
* METHOD_ERR gets returned on devices where few commands are not supported
* for example command to get WWAN Antenna type command is not supported on
* some devices.
*/
if (*output & METHOD_ERR)
return -ENODEV;
return 0;
}
static int get_wwan_antenna(int *wwan_antennatype)
{
int output, err;
/* Get current Antenna type */
err = dprc_command(DPRC_GET_WWAN_ANTENNA_TYPE, &output);
if (err)
return err;
if (output & DPRC_WWAN_ANTENNA_TYPE_A_BIT)
*wwan_antennatype = 1;
else if (output & DPRC_WWAN_ANTENNA_TYPE_B_BIT)
*wwan_antennatype = 2;
else
return -ENODEV;
return 0;
}
/* sysfs wwan antenna type entry */
static ssize_t wwan_antenna_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
switch (wwan_antennatype) {
case 1:
return sysfs_emit(buf, "type a\n");
case 2:
return sysfs_emit(buf, "type b\n");
default:
return -ENODATA;
}
}
static DEVICE_ATTR_RO(wwan_antenna_type);
static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
{
int wwanantenna_err, err;
wwanantenna_err = get_wwan_antenna(&wwan_antennatype);
/*
* If support isn't available (ENODEV) then quit, but don't
* return an error.
*/
if (wwanantenna_err == -ENODEV)
return 0;
/* if there was an error return it */
if (wwanantenna_err && (wwanantenna_err != -ENODEV))
return wwanantenna_err;
else if (!wwanantenna_err)
has_antennatype = true;
if (has_antennatype) {
err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
if (err)
return err;
}
return 0;
}
static void dprc_exit(void)
{
if (has_antennatype)
sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
}
static struct ibm_struct dprc_driver_data = {
.name = "dprc",
.exit = dprc_exit,
};
/****************************************************************************
****************************************************************************
*
......@@ -11000,6 +11105,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = tpacpi_kbdlang_init,
.data = &kbdlang_driver_data,
},
{
.init = tpacpi_dprc_init,
.data = &dprc_driver_data,
},
};
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment