diff mbox

[v2,8/8] ath10k: add thermal sensor device support

Message ID 20141217102226.15964.32919.stgit@potku.adurom.net (mailing list archive)
State Accepted
Headers show

Commit Message

Kalle Valo Dec. 17, 2014, 10:22 a.m. UTC
From: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>

Temperature sensor generates electrical analog voltage from temperature
of each chain. The analog voltage is converted to digital value through
ADC. For reading temperature values fom user space, hw monitoring device
is used.

Whenever the user requests for current temperature, the driver sends WMI
command and wait for response. For reading temperature,

cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input

Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c    |    2 +
 drivers/net/wireless/ath/ath10k/thermal.c |   83 +++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/thermal.h |   14 +++++
 drivers/net/wireless/ath/ath10k/wmi.c     |    1 
 4 files changed, 100 insertions(+)

Comments

Sebastian Gottschall Dec. 17, 2014, 6:56 p.m. UTC | #1
the whole code will not work. the firmware 10.2.4 returns op_version 3
so this check here fails

if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)

since 5 is required


  ath10k_pci 0000:01:00.0: qca988x hw2.0 (0x4100016c, 0x043202ff) fw 10.2.4.13-1 api 4 htt 2.1 wmi 3 cal otp max_sta 128

as you see. wmi api version is still 3

the reason is simple. the FW_IE_WMI_OP_VERSION is not included in the 10.2.4 firmware image. check by yourself



Sebastian




Am 17.12.2014 um 11:22 schrieb Kalle Valo:
> From: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
>
> Temperature sensor generates electrical analog voltage from temperature
> of each chain. The analog voltage is converted to digital value through
> ADC. For reading temperature values fom user space, hw monitoring device
> is used.
>
> Whenever the user requests for current temperature, the driver sends WMI
> command and wait for response. For reading temperature,
>
> cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input
>
> Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
> ---
>   drivers/net/wireless/ath/ath10k/core.c    |    2 +
>   drivers/net/wireless/ath/ath10k/thermal.c |   83 +++++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath10k/thermal.h |   14 +++++
>   drivers/net/wireless/ath/ath10k/wmi.c     |    1
>   4 files changed, 100 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
> index 28bfacb382f3..7d5a7b3add52 100644
> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -847,6 +847,7 @@ static void ath10k_core_restart(struct work_struct *work)
>   	complete_all(&ar->offchan_tx_completed);
>   	complete_all(&ar->install_key_done);
>   	complete_all(&ar->vdev_setup_done);
> +	complete_all(&ar->thermal.wmi_sync);
>   	wake_up(&ar->htt.empty_tx_wq);
>   	wake_up(&ar->wmi.tx_credits_wq);
>   	wake_up(&ar->peer_mapping_wq);
> @@ -1322,6 +1323,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
>   
>   	init_completion(&ar->install_key_done);
>   	init_completion(&ar->vdev_setup_done);
> +	init_completion(&ar->thermal.wmi_sync);
>   
>   	INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
>   
> diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
> index e98ce8ce27e2..d93913538d18 100644
> --- a/drivers/net/wireless/ath/ath10k/thermal.c
> +++ b/drivers/net/wireless/ath/ath10k/thermal.c
> @@ -17,6 +17,8 @@
>   #include <linux/device.h>
>   #include <linux/sysfs.h>
>   #include <linux/thermal.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
>   #include "core.h"
>   #include "debug.h"
>   #include "wmi-ops.h"
> @@ -119,9 +121,72 @@ static struct thermal_cooling_device_ops ath10k_thermal_ops = {
>   	.set_cur_state = ath10k_thermal_set_cur_dutycycle,
>   };
>   
> +static ssize_t ath10k_thermal_show_temp(struct device *dev,
> +					struct device_attribute *attr,
> +					char *buf)
> +{
> +	struct ath10k *ar = dev_get_drvdata(dev);
> +	int ret, temperature;
> +
> +	mutex_lock(&ar->conf_mutex);
> +
> +	/* Can't get temperature when the card is off */
> +	if (ar->state != ATH10K_STATE_ON) {
> +		ret = -ENETDOWN;
> +		goto out;
> +	}
> +
> +	reinit_completion(&ar->thermal.wmi_sync);
> +	ret = ath10k_wmi_pdev_get_temperature(ar);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to read temperature %d\n", ret);
> +		goto out;
> +	}
> +
> +	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
> +		ret = -ESHUTDOWN;
> +		goto out;
> +	}
> +
> +	ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
> +					  ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
> +	if (ret == 0) {
> +		ath10k_warn(ar, "failed to synchronize thermal read\n");
> +		ret = -ETIMEDOUT;
> +		goto out;
> +	}
> +
> +	spin_lock_bh(&ar->data_lock);
> +	temperature = ar->thermal.temperature;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	ret = snprintf(buf, PAGE_SIZE, "%d", temperature);
> +out:
> +	mutex_unlock(&ar->conf_mutex);
> +	return ret;
> +}
> +
> +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
> +{
> +	spin_lock_bh(&ar->data_lock);
> +	ar->thermal.temperature = temperature;
> +	spin_unlock_bh(&ar->data_lock);
> +	complete(&ar->thermal.wmi_sync);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp,
> +			  NULL, 0);
> +
> +static struct attribute *ath10k_hwmon_attrs[] = {
> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> +	NULL,
> +};
> +ATTRIBUTE_GROUPS(ath10k_hwmon);
> +
>   int ath10k_thermal_register(struct ath10k *ar)
>   {
>   	struct thermal_cooling_device *cdev;
> +	struct device *hwmon_dev;
>   	int ret;
>   
>   	cdev = thermal_cooling_device_register("ath10k_thermal", ar,
> @@ -141,8 +206,26 @@ int ath10k_thermal_register(struct ath10k *ar)
>   	}
>   
>   	ar->thermal.cdev = cdev;
> +
> +	/* Do not register hwmon device when temperature reading is not
> +	 * supported by firmware
> +	 */
> +	if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
> +		return 0;
> +
> +	hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
> +							   "ath10k_hwmon", ar,
> +							   ath10k_hwmon_groups);
> +	if (IS_ERR(hwmon_dev)) {
> +		ath10k_err(ar, "failed to register hwmon device: %ld\n",
> +			   PTR_ERR(hwmon_dev));
> +		ret = -EINVAL;
> +		goto err_remove_link;
> +	}
>   	return 0;
>   
> +err_remove_link:
> +	sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
>   err_cooling_destroy:
>   	thermal_cooling_device_unregister(cdev);
>   	return ret;
> diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
> index e20bb87849ae..bccc17ae0fde 100644
> --- a/drivers/net/wireless/ath/ath10k/thermal.h
> +++ b/drivers/net/wireless/ath/ath10k/thermal.h
> @@ -20,17 +20,25 @@
>   #define ATH10K_QUIET_PERIOD_MIN         25
>   #define ATH10K_QUIET_START_OFFSET       10
>   #define ATH10K_QUIET_DUTY_CYCLE_MAX     70
> +#define ATH10K_HWMON_NAME_LEN           15
> +#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
>   
>   struct ath10k_thermal {
>   	struct thermal_cooling_device *cdev;
> +	struct completion wmi_sync;
>   
>   	/* protected by conf_mutex */
>   	u32 duty_cycle;
> +	/* temperature value in Celcius degree
> +	 * protected by data_lock
> +	 */
> +	int temperature;
>   };
>   
>   #ifdef CONFIG_THERMAL
>   int ath10k_thermal_register(struct ath10k *ar);
>   void ath10k_thermal_unregister(struct ath10k *ar);
> +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
>   #else
>   static inline int ath10k_thermal_register(struct ath10k *ar)
>   {
> @@ -40,5 +48,11 @@ static inline int ath10k_thermal_register(struct ath10k *ar)
>   static inline void ath10k_thermal_unregister(struct ath10k *ar)
>   {
>   }
> +
> +static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
> +						    int temperature)
> +{
> +}
> +
>   #endif
>   #endif /* _THERMAL_ */
> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index c2d7ac31fd78..ac742905331b 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -3038,6 +3038,7 @@ static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
>   	if (WARN_ON(skb->len < sizeof(*ev)))
>   		return -EPROTO;
>   
> +	ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
>   	return 0;
>   }
>   
>
>
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
>
Kalle Valo Dec. 23, 2014, 5:43 p.m. UTC | #2
Sebastian Gottschall <s.gottschall@dd-wrt.com> writes:

> the whole code will not work. the firmware 10.2.4 returns op_version 3
> so this check here fails
>
> if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
>
> since 5 is required

I know, I used firmware-4.bin_10.2.4.13-2 to test this. I just didn't
have a chance to upload it until now:

https://github.com/kvalo/ath10k-firmware/tree/master/10.2.4
Sebastian Gottschall Dec. 23, 2014, 7:52 p.m. UTC | #3
Am 23.12.2014 um 18:43 schrieb Kalle Valo:
> Sebastian Gottschall <s.gottschall@dd-wrt.com> writes:
>
>> the whole code will not work. the firmware 10.2.4 returns op_version 3
>> so this check here fails
>>
>> if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
>>
>> since 5 is required
> I know, I used firmware-4.bin_10.2.4.13-2 to test this. I just didn't
> have a chance to upload it until now:
>
> https://github.com/kvalo/ath10k-firmware/tree/master/10.2.4
:-) thanks
i tested it using a hardcoded api version patch based on the firmware 
version  and it worked as well so far. (just tested temperture sensor 
readout)

Sebastian
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 28bfacb382f3..7d5a7b3add52 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -847,6 +847,7 @@  static void ath10k_core_restart(struct work_struct *work)
 	complete_all(&ar->offchan_tx_completed);
 	complete_all(&ar->install_key_done);
 	complete_all(&ar->vdev_setup_done);
+	complete_all(&ar->thermal.wmi_sync);
 	wake_up(&ar->htt.empty_tx_wq);
 	wake_up(&ar->wmi.tx_credits_wq);
 	wake_up(&ar->peer_mapping_wq);
@@ -1322,6 +1323,7 @@  struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 
 	init_completion(&ar->install_key_done);
 	init_completion(&ar->vdev_setup_done);
+	init_completion(&ar->thermal.wmi_sync);
 
 	INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
 
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
index e98ce8ce27e2..d93913538d18 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.c
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -17,6 +17,8 @@ 
 #include <linux/device.h>
 #include <linux/sysfs.h>
 #include <linux/thermal.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include "core.h"
 #include "debug.h"
 #include "wmi-ops.h"
@@ -119,9 +121,72 @@  static struct thermal_cooling_device_ops ath10k_thermal_ops = {
 	.set_cur_state = ath10k_thermal_set_cur_dutycycle,
 };
 
+static ssize_t ath10k_thermal_show_temp(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct ath10k *ar = dev_get_drvdata(dev);
+	int ret, temperature;
+
+	mutex_lock(&ar->conf_mutex);
+
+	/* Can't get temperature when the card is off */
+	if (ar->state != ATH10K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto out;
+	}
+
+	reinit_completion(&ar->thermal.wmi_sync);
+	ret = ath10k_wmi_pdev_get_temperature(ar);
+	if (ret) {
+		ath10k_warn(ar, "failed to read temperature %d\n", ret);
+		goto out;
+	}
+
+	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
+					  ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
+	if (ret == 0) {
+		ath10k_warn(ar, "failed to synchronize thermal read\n");
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	spin_lock_bh(&ar->data_lock);
+	temperature = ar->thermal.temperature;
+	spin_unlock_bh(&ar->data_lock);
+
+	ret = snprintf(buf, PAGE_SIZE, "%d", temperature);
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
+{
+	spin_lock_bh(&ar->data_lock);
+	ar->thermal.temperature = temperature;
+	spin_unlock_bh(&ar->data_lock);
+	complete(&ar->thermal.wmi_sync);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp,
+			  NULL, 0);
+
+static struct attribute *ath10k_hwmon_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(ath10k_hwmon);
+
 int ath10k_thermal_register(struct ath10k *ar)
 {
 	struct thermal_cooling_device *cdev;
+	struct device *hwmon_dev;
 	int ret;
 
 	cdev = thermal_cooling_device_register("ath10k_thermal", ar,
@@ -141,8 +206,26 @@  int ath10k_thermal_register(struct ath10k *ar)
 	}
 
 	ar->thermal.cdev = cdev;
+
+	/* Do not register hwmon device when temperature reading is not
+	 * supported by firmware
+	 */
+	if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
+		return 0;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
+							   "ath10k_hwmon", ar,
+							   ath10k_hwmon_groups);
+	if (IS_ERR(hwmon_dev)) {
+		ath10k_err(ar, "failed to register hwmon device: %ld\n",
+			   PTR_ERR(hwmon_dev));
+		ret = -EINVAL;
+		goto err_remove_link;
+	}
 	return 0;
 
+err_remove_link:
+	sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
 err_cooling_destroy:
 	thermal_cooling_device_unregister(cdev);
 	return ret;
diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
index e20bb87849ae..bccc17ae0fde 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.h
+++ b/drivers/net/wireless/ath/ath10k/thermal.h
@@ -20,17 +20,25 @@ 
 #define ATH10K_QUIET_PERIOD_MIN         25
 #define ATH10K_QUIET_START_OFFSET       10
 #define ATH10K_QUIET_DUTY_CYCLE_MAX     70
+#define ATH10K_HWMON_NAME_LEN           15
+#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
 
 struct ath10k_thermal {
 	struct thermal_cooling_device *cdev;
+	struct completion wmi_sync;
 
 	/* protected by conf_mutex */
 	u32 duty_cycle;
+	/* temperature value in Celcius degree
+	 * protected by data_lock
+	 */
+	int temperature;
 };
 
 #ifdef CONFIG_THERMAL
 int ath10k_thermal_register(struct ath10k *ar);
 void ath10k_thermal_unregister(struct ath10k *ar);
+void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
 #else
 static inline int ath10k_thermal_register(struct ath10k *ar)
 {
@@ -40,5 +48,11 @@  static inline int ath10k_thermal_register(struct ath10k *ar)
 static inline void ath10k_thermal_unregister(struct ath10k *ar)
 {
 }
+
+static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
+						    int temperature)
+{
+}
+
 #endif
 #endif /* _THERMAL_ */
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2d7ac31fd78..ac742905331b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3038,6 +3038,7 @@  static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
 	if (WARN_ON(skb->len < sizeof(*ev)))
 		return -EPROTO;
 
+	ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
 	return 0;
 }