diff mbox series

[2/2] platorm/x86: thinkpad_acpi: sysfs interface to interface to get wwan antenna type

Message ID 20210212055856.232702-2-njoshi1@lenovo.com (mailing list archive)
State Changes Requested, archived
Headers show
Series [1/2] platorm/x86: thinkpad_acpi: sysfs interface to reduce wlan tx power | expand

Commit Message

Nitin Joshi Feb. 12, 2021, 5:58 a.m. UTC
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>
---
 .../admin-guide/laptops/thinkpad-acpi.rst     | 21 +++++++
 drivers/platform/x86/thinkpad_acpi.c          | 55 ++++++++++++++++++-
 2 files changed, 74 insertions(+), 2 deletions(-)

Comments

Barnabás Pőcze Feb. 13, 2021, 8:43 p.m. UTC | #1
Hi


2021. február 12., péntek 6:58 keltezéssel, Nitin Joshi írta:

> [...]
> +/* 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 sysfs_emit(buf, "unknown type\n");

I feel like returning -ENODATA would be more appropriate here. Or maybe you could choose
not to create the attribute if the antenna type is unknown. And I'm not sure if
the "type" prefix is necessary. I believe the name of the attribute 'wwan_antenna_type'
already implies that the content will describe a type. Furthermore, I think you could
omit the `has_antennatype` variable altogether, storing only `wwan_antennatype` is enough.


> +	}
> +}
> +
>  static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
>  				struct device_attribute *attr,
>  				const char *buf, size_t count)
> @@ -10076,24 +10114,29 @@ static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
>  	}
>
>  	sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "wlan_tx_strength_reduce");
> +

If you want the empty line here, I think you should place it in the previous patch.


>  	return count;
>  }
>  static DEVICE_ATTR_RW(wlan_tx_strength_reduce);
> +static DEVICE_ATTR_RO(wwan_antenna_type);
>
>  static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
>  {
> -	int wlantx_err, err;
> +	int wlantx_err, wwanantenna_err, err;
>
>  	wlantx_err = get_wlan_state(&has_wlantxreduce, &wlan_txreduce);
> +	wwanantenna_err = get_wwan_antenna(&has_antennatype, &wwan_antennatype);
>  	/*
>  	 * If support isn't available (ENODEV) for both devices then quit, but
>  	 * don't return an error.
>  	 */
> -	if (wlantx_err == -ENODEV)
> +	if ((wlantx_err == -ENODEV) && (wwanantenna_err == -ENODEV))
>  		return 0;
>  	/* Otherwise, if there was an error return it */
>  	if (wlantx_err && (wlantx_err != -ENODEV))
>  		return wlantx_err;
> +	if (wwanantenna_err && (wwanantenna_err != -ENODEV))
> +		return wwanantenna_err;
>
>  	if (has_wlantxreduce) {
>  		err = sysfs_create_file(&tpacpi_pdev->dev.kobj,
> @@ -10101,6 +10144,12 @@ static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
>  		if (err)
>  			return err;
>  	}
> +
> +	if (has_antennatype) {
> +		err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
> +		if (err)
> +			return err;
> +	}
>  	return 0;
>  }
> [...]


Regards,
Barnabás Pőcze
Nitin Joshi1 Feb. 15, 2021, 9:07 a.m. UTC | #2
Hi

>-----Original Message-----
>From: Barnabás Pőcze <pobrn@protonmail.com>
>Sent: Sunday, February 14, 2021 5:43 AM
>To: Nitin Joshi <nitjoshi@gmail.com>
>Cc: hdegoede@redhat.com; ibm-acpi-devel@lists.sourceforge.net; platform-
>driver-x86@vger.kernel.org; Nitin Joshi1 <njoshi1@lenovo.com>; Mark RH
>Pearson <markpearson@lenovo.com>
>Subject: [External] Re: [PATCH 2/2] platorm/x86: thinkpad_acpi: sysfs
>interface to interface to get wwan antenna type
>
>Hi
>
>
>2021. február 12., péntek 6:58 keltezéssel, Nitin Joshi írta:
>
>> [...]
>> +/* 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 sysfs_emit(buf, "unknown type\n");
>
>I feel like returning -ENODATA would be more appropriate here. Or maybe
>you could choose not to create the attribute if the antenna type is unknown.
>And I'm not sure if the "type" prefix is necessary. I believe the name of the
>attribute 'wwan_antenna_type'
Ack . I will check it. 
Regarding prefix, it's not so necessary but let me keep "type" prefix.
   
>already implies that the content will describe a type. Furthermore, I think you
>could omit the `has_antennatype` variable altogether, storing only
>`wwan_antennatype` is enough.
Ack . I will check it
>
>
>> +	}
>> +}
>> +
>>  static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
>>  				struct device_attribute *attr,
>>  				const char *buf, size_t count)
>> @@ -10076,24 +10114,29 @@ static ssize_t
>wlan_tx_strength_reduce_store(struct device *dev,
>>  	}
>>
>>  	sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
>> "wlan_tx_strength_reduce");
>> +
>
>If you want the empty line here, I think you should place it in the previous
>patch.
Ack . I will remove it.
>
>
>>  	return count;
>>  }
>>  static DEVICE_ATTR_RW(wlan_tx_strength_reduce);
>> +static DEVICE_ATTR_RO(wwan_antenna_type);
>>
>>  static int tpacpi_dprc_init(struct ibm_init_struct *iibm)  {
>> -	int wlantx_err, err;
>> +	int wlantx_err, wwanantenna_err, err;
>>
>>  	wlantx_err = get_wlan_state(&has_wlantxreduce, &wlan_txreduce);
>> +	wwanantenna_err = get_wwan_antenna(&has_antennatype,
>&wwan_antennatype);
>>  	/*
>>  	 * If support isn't available (ENODEV) for both devices then quit, but
>>  	 * don't return an error.
>>  	 */
>> -	if (wlantx_err == -ENODEV)
>> +	if ((wlantx_err == -ENODEV) && (wwanantenna_err == -ENODEV))
>>  		return 0;
>>  	/* Otherwise, if there was an error return it */
>>  	if (wlantx_err && (wlantx_err != -ENODEV))
>>  		return wlantx_err;
>> +	if (wwanantenna_err && (wwanantenna_err != -ENODEV))
>> +		return wwanantenna_err;
>>
>>  	if (has_wlantxreduce) {
>>  		err = sysfs_create_file(&tpacpi_pdev->dev.kobj,
>> @@ -10101,6 +10144,12 @@ static int tpacpi_dprc_init(struct
>ibm_init_struct *iibm)
>>  		if (err)
>>  			return err;
>>  	}
>> +
>> +	if (has_antennatype) {
>> +		err = sysfs_create_file(&tpacpi_pdev->dev.kobj,
>&dev_attr_wwan_antenna_type.attr);
>> +		if (err)
>> +			return err;
>> +	}
>>  	return 0;
>>  }
>> [...]
>
>
>Regards,
>Barnabás Pőcze

Thanks & regards,
Nitin Joshi
diff mbox series

Patch

diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
index 10410811b990..df6904f23dea 100644
--- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst
+++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
@@ -52,6 +52,7 @@  detailed description):
 	- LCD Shadow (PrivacyGuard) enable and disable
 	- Lap mode sensor
 	- WLAN transmission power control
+	- 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
@@ -1465,6 +1466,26 @@  The available commands are::
 The first command restores the wlan transmission power and the latter one
 reduces wlan transmission power.
 
+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.
+
 EXPERIMENTAL: UWB
 -----------------
 
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 6dbbd4a14264..db016a2a1837 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -9990,8 +9990,11 @@  static struct ibm_struct proxsensor_driver_data = {
 #define DPRC_GET_WLAN_STATE             0x20000
 #define DPRC_SET_WLAN_POWER_REDUCE      0x00030010
 #define DPRC_SET_WLAN_POWER_FULL        0x00030100
+#define DPRC_GET_WWAN_ANTENNA_TYPE      0x40000
 static int has_wlantxreduce;
 static int wlan_txreduce;
+static int has_antennatype;
+static int wwan_antennatype;
 
 static int dprc_command(int command, int *output)
 {
@@ -10035,6 +10038,26 @@  static int get_wlan_state(int *has_wlantxreduce, int *wlan_txreduce)
 	return 0;
 }
 
+static int get_wwan_antenna(int *has_antennatype, 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 & BIT(4))
+		*wwan_antennatype = 1;
+	else if (output & BIT(8))
+		*wwan_antennatype = 2;
+	else
+		*wwan_antennatype = -1;
+
+	*has_antennatype = 1;
+	return 0;
+}
+
 /* sysfs wlan entry */
 static ssize_t wlan_tx_strength_reduce_show(struct device *dev,
 				struct device_attribute *attr,
@@ -10049,6 +10072,21 @@  static ssize_t wlan_tx_strength_reduce_show(struct device *dev,
 	return sysfs_emit(buf, "%d\n", wlan_txreduce);
 }
 
+/* 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 sysfs_emit(buf, "unknown type\n");
+	}
+}
+
 static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
@@ -10076,24 +10114,29 @@  static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
 	}
 
 	sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "wlan_tx_strength_reduce");
+
 	return count;
 }
 static DEVICE_ATTR_RW(wlan_tx_strength_reduce);
+static DEVICE_ATTR_RO(wwan_antenna_type);
 
 static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
 {
-	int wlantx_err, err;
+	int wlantx_err, wwanantenna_err, err;
 
 	wlantx_err = get_wlan_state(&has_wlantxreduce, &wlan_txreduce);
+	wwanantenna_err = get_wwan_antenna(&has_antennatype, &wwan_antennatype);
 	/*
 	 * If support isn't available (ENODEV) for both devices then quit, but
 	 * don't return an error.
 	 */
-	if (wlantx_err == -ENODEV)
+	if ((wlantx_err == -ENODEV) && (wwanantenna_err == -ENODEV))
 		return 0;
 	/* Otherwise, if there was an error return it */
 	if (wlantx_err && (wlantx_err != -ENODEV))
 		return wlantx_err;
+	if (wwanantenna_err && (wwanantenna_err != -ENODEV))
+		return wwanantenna_err;
 
 	if (has_wlantxreduce) {
 		err = sysfs_create_file(&tpacpi_pdev->dev.kobj,
@@ -10101,6 +10144,12 @@  static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
 		if (err)
 			return err;
 	}
+
+	if (has_antennatype) {
+		err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
+		if (err)
+			return err;
+	}
 	return 0;
 }
 
@@ -10108,6 +10157,8 @@  static void dprc_exit(void)
 {
 	if (has_wlantxreduce)
 		sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wlan_tx_strength_reduce.attr);
+	if (has_antennatype)
+		sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
 }
 
 static struct ibm_struct dprc_driver_data = {