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: Mark Pearson <markpearson@lenovo.com> Signed-off-by: Nitin Joshi <njoshi1@lenovo.com> Link: https://lore.kernel.org/r/20210317024636.356175-1-njoshi1@lenovo.com Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
2728f39dfc
commit
3feb52a2b8
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue