linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: viktor.barna@celeno.com
To: linux-wireless@vger.kernel.org
Cc: Kalle Valo <kvalo@codeaurora.org>,
	"David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	Aviad Brikman <aviad.brikman@celeno.com>,
	Eliav Farber <eliav.farber@gmail.com>,
	Maksym Kokhan <maksym.kokhan@celeno.com>,
	Oleksandr Savchenko <oleksandr.savchenko@celeno.com>,
	Shay Bar <shay.bar@celeno.com>,
	Viktor Barna <viktor.barna@celeno.com>
Subject: [RFC v2 80/96] cl8k: add temperature.c
Date: Tue, 24 May 2022 14:34:46 +0300	[thread overview]
Message-ID: <20220524113502.1094459-81-viktor.barna@celeno.com> (raw)
In-Reply-To: <20220524113502.1094459-1-viktor.barna@celeno.com>

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/temperature.c    | 634 ++++++++++++++++++
 1 file changed, 634 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.c

diff --git a/drivers/net/wireless/celeno/cl8k/temperature.c b/drivers/net/wireless/celeno/cl8k/temperature.c
new file mode 100644
index 000000000000..f3c773d957f6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/temperature.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/kthread.h>
+
+#include "hw.h"
+#include "e2p.h"
+#include "channel.h"
+#include "power.h"
+#include "debug.h"
+#include "utils.h"
+#include "radio.h"
+#include "temperature.h"
+
+#define TEMP_DIFF_INVALID 0x7F
+
+#define TEMPERATURE_MIN 0
+#define TEMPERATURE_MAX 127
+
+#define DUTY_CYCLE_MAX  100
+#define DUTY_CYCLE_MIN  20
+#define DUTY_CYCLE_STEP 20
+
+#define TEMP_MEASUREMENT_TIMEOUT msecs_to_jiffies(500)
+
+static int cl_temperature_read_fw(struct cl_hw *cl_hw, enum cl_temp_mode desired_temp_mode,
+				  u16 *raw_bits)
+{
+	u8 retval = 0;
+	struct mm_anamon_read_cfm *cfm;
+
+	if (cl_msg_tx_anamon_read(cl_hw, ANAMON_MODE_TEMPERATURE, desired_temp_mode, 0) != 0) {
+		cl_dbg_err(cl_hw, "cl_msg_tx_anamon_read failed\n");
+		cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+		return -1;
+	}
+
+	cfm = (struct mm_anamon_read_cfm *)(cl_hw->msg_cfm_params[MM_ANAMON_READ_CFM]);
+	if (!cfm)
+		return -ENOMSG;
+
+	retval = cfm->retval;
+	*raw_bits = ((le16_to_cpu(cfm->raw_bits_data_0) + le16_to_cpu(cfm->raw_bits_data_1)) / 2);
+	cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+
+	return retval ? 0 : -1;
+}
+
+static s16 cl_raw_bits_to_temperature(u16 raw_bits, enum cl_temp_mode desired_temp_mode)
+{
+	s16 adcmv = cl_adc_to_mv(raw_bits);
+
+	/* Calculation of external thermistor */
+	if (desired_temp_mode == TEMP_MODE_EXTERNAL) {
+		/*
+		 * External-temperature calculation:
+		 * Ext_tmp = -196 * adcv ^ 3 + 403 * adcv ^ 2 - 356 * adcv + 146
+		 *
+		 * Ext_tmp = -196 * (adcmv / 1000) ^ 3 +
+		 *           403 * (adcmv / 1000) ^ 2 -
+		 *           356 * (adcmv / 1000) +
+		 *           146
+		 *
+		 * Ext_tmp = (-196 * adcmv ^ 3 +
+		 *            403000 * adcmv ^ 2 -
+		 *            356000000 * adcmv +
+		 *            146000000000) / 1000000000
+		 */
+		return (s16)div_s64(-196ULL * adcmv * adcmv * adcmv +
+				    403000ULL * adcmv * adcmv -
+				    356000000ULL * adcmv +
+				    146000000000ULL,
+				    1000000000);
+	}
+
+	/* Calculation of internal thermistor - ADCmv * slope - 163 (slope=0.290) */
+	if (desired_temp_mode == TEMP_MODE_INTERNAL)
+		return ((adcmv * 29) / 100) - 163;
+
+	return 0;
+}
+
+static void cl_temperature_set_power_offset(struct cl_hw *cl_hw, s8 power_offset)
+{
+	s8 total_pwr_offset[MAX_ANTENNAS] = {0};
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	u8 i = 0;
+
+	cl_hw->temp_comp_db.power_offset = power_offset;
+
+	if (chan_idx == INVALID_CHAN_IDX)
+		goto out;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		total_pwr_offset[i] =
+			(cl_hw->tx_pow_info[chan_idx][i].offset +
+			 POWER_OFFSET_RES * power_offset);
+	}
+
+out:
+	cl_msg_tx_set_ant_pwr_offset(cl_hw, total_pwr_offset);
+}
+
+static void cl_temperature_comp_tcv(struct cl_chip *chip, struct cl_hw *cl_hw, s16 temp_internal)
+{
+	struct cl_temp_comp_db *temp_comp_db = &cl_hw->temp_comp_db;
+	s8 new_power_offset = 0;
+
+	/* Accumulate temperature delta */
+	temp_comp_db->acc_temp_delta += (temp_internal - temp_comp_db->calib_temperature);
+
+	/* Check if it is time to make a new decision */
+	if ((chip->temperature.comp_iterations % CL_TEMP_COMP_ITERATIONS) != 0)
+		return;
+
+	/* Average the temperature delta over the last CL_TEMP_COMP_ITERATIONS samples */
+	temp_comp_db->avg_temp_delta = DIV_ROUND_CLOSEST(temp_comp_db->acc_temp_delta,
+							 CL_TEMP_COMP_ITERATIONS);
+
+	/* Reset accumulated temp delta */
+	temp_comp_db->acc_temp_delta = 0;
+
+	new_power_offset = (s8)DIV_ROUND_CLOSEST(temp_comp_db->avg_temp_delta *
+						 cl_hw->conf->ce_temp_comp_slope, 100);
+
+	if (temp_comp_db->power_offset == new_power_offset)
+		return;
+
+	cl_dbg_trace(cl_hw, "calib_temperature %d, avg_temp_delta %d, power_offset %d\n",
+		     temp_comp_db->calib_temperature,
+		     temp_comp_db->avg_temp_delta,
+		     new_power_offset);
+
+	cl_temperature_set_power_offset(cl_hw, new_power_offset);
+}
+
+static void cl_temperature_comp(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	s16 temp_internal = 0;
+
+	if (!chip->conf->ce_temp_comp_en)
+		return;
+
+	temp_internal = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL);
+	temperature->comp_iterations++;
+
+	cl_dbg_chip_trace(chip, "comp_iterations = %u, temp_internal = %d\n",
+			  (temperature->comp_iterations % CL_TEMP_COMP_ITERATIONS), temp_internal);
+
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_temperature_comp_tcv(chip, chip->cl_hw_tcv0, temp_internal);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_temperature_comp_tcv(chip, chip->cl_hw_tcv1, temp_internal);
+}
+
+static void cl_temperature_tx_duty_cycle(struct cl_chip *chip, u8 duty_cycle)
+{
+	u16 periodic_tx_time_on = chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+	u16 periodic_tx_time_off = chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv0,
+						 periodic_tx_time_off, periodic_tx_time_on);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv1,
+						 periodic_tx_time_off, periodic_tx_time_on);
+}
+
+static void cl_temperature_protect_radio_off(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->force_radio_off)
+		return;
+
+	cl_radio_off_chip(chip);
+	temp_protect_db->force_radio_off = true;
+	cl_dbg_chip_verbose(chip, "temperature [%d] >= radio off threshold [%d] --> radio off!\n",
+			    temp_avg, conf->ce_temp_protect_radio_off_th);
+}
+
+static void cl_temperature_protect_radio_on(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+	s16 temp_thr = conf->ce_temp_protect_radio_off_th - CL_TEMP_PROTECT_RADIO_OFF_HYST;
+
+	if (temp_avg >= temp_thr)
+		return;
+
+	cl_radio_on_chip(chip);
+	temp_protect_db->force_radio_off = false;
+	cl_dbg_chip_verbose(chip, "temperature [%d] < radio off threshold - hysteresis [%d] "
+				  "--> radio on!\n",
+			    temp_avg, temp_thr);
+}
+
+static void cl_temperature_protect_dec_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->duty_cycle == DUTY_CYCLE_MIN)
+		return;
+
+	temp_protect_db->duty_cycle -= DUTY_CYCLE_STEP;
+	cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+	cl_dbg_chip_warn(chip,
+			 "temperature [%d] > protect_th_max [%d] --> decrease duty cycle [%u]!\n",
+			 temp_avg, conf->ce_temp_protect_th_max, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_inc_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->duty_cycle == DUTY_CYCLE_MAX)
+		return;
+
+	temp_protect_db->duty_cycle += DUTY_CYCLE_STEP;
+	cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+	cl_dbg_chip_warn(chip,
+			 "temperature [%d] < protect_th_min [%d] --> increase duty cycle [%u]!\n",
+			 temp_avg, conf->ce_temp_protect_th_min, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_decision(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	/* Test mode - force test_mode_duty_cycle */
+	if (unlikely(temp_protect_db->test_mode_duty_cycle != DUTY_CYCLE_MAX)) {
+		cl_temperature_tx_duty_cycle(chip, temp_protect_db->test_mode_duty_cycle);
+		return;
+	}
+
+	/* Temperature protection logic:
+	 *
+	 * If the temperature is greater or equal to the radio off threshold
+	 * then set the radio off.
+	 * If the temperature is below the (radio off threshold - hysteresis [10])
+	 * then set the radio on again.
+	 *
+	 * Any time the temperature is greater than the max threshold then we
+	 * decrease the duty cycle.
+	 * Any time the temperature is below the min threshold then we increase
+	 * the duty cycle.
+	 */
+	if (temp_avg >= conf->ce_temp_protect_radio_off_th) {
+		cl_temperature_protect_radio_off(chip, temp_avg);
+		return;
+	}
+
+	if (temp_protect_db->force_radio_off) {
+		cl_temperature_protect_radio_on(chip, temp_avg);
+		return;
+	}
+
+	if (temp_avg > conf->ce_temp_protect_th_max) {
+		cl_temperature_protect_dec_duty_cycle(chip, temp_avg);
+		return;
+	}
+
+	if (temp_avg < chip->conf->ce_temp_protect_th_min) {
+		cl_temperature_protect_inc_duty_cycle(chip, temp_avg);
+		return;
+	}
+}
+
+static s16 cl_temperature_avg_protect(struct cl_temp_protect_db *temp_protect_db)
+{
+	/* Calculate average of last_samples */
+	u8 i;
+	s32 temp_avg = 0;
+
+	for (i = 0; i < CL_TEMP_PROTECT_NUM_SAMPLES; i++)
+		temp_avg += temp_protect_db->last_samples[i];
+
+	return (s16)(temp_avg / CL_TEMP_PROTECT_NUM_SAMPLES);
+}
+
+static void cl_temperature_protect_handle_read(struct cl_chip *chip, s16 temp)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	unsigned long curr_time = jiffies_to_msecs(jiffies);
+	unsigned long delta_time = curr_time - temp_protect_db->last_timestamp;
+
+	/* Add current read */
+	temp_protect_db->last_samples[temp_protect_db->curr_idx] = temp;
+	temp_protect_db->curr_idx = (temp_protect_db->curr_idx + 1) % CL_TEMP_PROTECT_NUM_SAMPLES;
+
+	if (delta_time >= CL_TEMP_PROTECT_INTERVAL_MS) {
+		s16 temp_avg = cl_temperature_avg_protect(temp_protect_db);
+
+		cl_dbg_chip_trace(chip, "temp_avg = %d, delta_time = %lu\n", temp_avg, delta_time);
+		cl_temperature_protect_decision(chip, temp_avg);
+		temp_protect_db->last_timestamp = curr_time;
+	}
+}
+
+static void cl_temperature_protect(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	s16 protect_temp = 0;
+	struct cl_chip_conf *conf = chip->conf;
+
+	switch (conf->ce_temp_protect_en) {
+	case TEMP_PROTECT_OFF:
+		return;
+	case TEMP_PROTECT_INTERNAL:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) +
+			conf->ce_temp_protect_delta;
+		break;
+	case TEMP_PROTECT_EXTERNAL:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL) +
+			conf->ce_temp_protect_delta;
+		break;
+	case TEMP_PROTECT_DIFF:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+			chip->temperature.diff_internal_external + conf->ce_temp_protect_delta;
+		break;
+	}
+
+	cl_temperature_protect_handle_read(chip, protect_temp);
+}
+
+static int cl_e2p_read_temp_diff(struct cl_chip *chip, s8 *temp_diff)
+{
+	/* Read temp_diff from eeprom */
+	return cl_e2p_read(chip, temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_e2p_write_temp_diff(struct cl_chip *chip, s8 temp_diff)
+{
+	/* Writing temp_diff to eeprom */
+	return cl_e2p_write(chip, (u8 *)&temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_temperature_diff_update(struct cl_hw *cl_hw)
+{
+	s8 temp_diff = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+		cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL);
+
+	if (cl_e2p_write_temp_diff(cl_hw->chip, temp_diff)) {
+		cl_dbg_err(cl_hw, "Error occurred while writing temperature diff to EEPROM.\n");
+		return -1;
+	}
+
+	cl_hw->chip->temperature.diff_internal_external = temp_diff;
+	return 0;
+}
+
+static struct cl_hw *cl_init_measurement(struct cl_chip *chip)
+{
+	struct cl_hw *cl_hw = NULL;
+
+	mutex_lock(&chip->temperature.hw_lock);
+	cl_hw = cl_chip_is_tcv0_enabled(chip) ? chip->cl_hw_tcv0 : chip->cl_hw_tcv1;
+	if (cl_hw && test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+	    !(cl_hw->conf && cl_hw->conf->ce_listener_en))
+		set_bit(cl_hw->tcv_idx, &chip->temperature.used_hw_map);
+	else
+		cl_hw = NULL;
+	mutex_unlock(&chip->temperature.hw_lock);
+
+	return cl_hw;
+}
+
+static void cl_deinit_measurement(struct cl_hw *cl_hw)
+{
+	struct cl_temperature *temperature = &cl_hw->chip->temperature;
+
+	clear_bit(cl_hw->tcv_idx, &temperature->used_hw_map);
+	wake_up(&temperature->measurement_done);
+}
+
+void cl_temperature_wait_for_measurement(struct cl_chip *chip, u8 tcv_idx)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	int timeout = 0;
+
+	mutex_lock(&temperature->hw_lock);
+	if (!test_bit(tcv_idx, &temperature->used_hw_map))
+		goto exit;
+
+	timeout = wait_event_timeout(temperature->measurement_done,
+				     !test_bit(tcv_idx, &temperature->used_hw_map),
+				     TEMP_MEASUREMENT_TIMEOUT);
+	WARN_ONCE(timeout != 0, "Measurment timeout reached!\n");
+
+exit:
+	mutex_unlock(&temperature->hw_lock);
+}
+
+static int cl_temperature_kthread(void *arg)
+{
+	struct cl_chip *chip = (struct cl_chip *)arg;
+	struct cl_hw *cl_hw = NULL;
+	unsigned long timeout = msecs_to_jiffies(CL_TEMPERATURE_TIMER_INTERVAL_MS);
+
+	while (!kthread_should_stop()) {
+		cl_hw = cl_init_measurement(chip);
+		if (cl_hw) {
+			cl_temperature_comp(chip, cl_hw);
+			cl_temperature_protect(chip, cl_hw);
+			cl_deinit_measurement(cl_hw);
+		}
+
+		if (wait_event_timeout(chip->temperature.wait_done,
+				       kthread_should_stop(), timeout)) {
+			cl_dbg_chip_trace(chip, "exit temperature kthread\n");
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static void cl_temperature_recovery_protect(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (chip->conf->ce_temp_protect_en != TEMP_PROTECT_OFF) {
+		u8 duty_cycle = chip->temperature.protect_db.duty_cycle;
+
+		if (duty_cycle < DUTY_CYCLE_MAX) {
+			u16 periodic_tx_time_on =
+				chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+			u16 periodic_tx_time_off =
+				chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+			cl_msg_tx_start_periodic_tx_time(cl_hw, periodic_tx_time_off,
+							 periodic_tx_time_on);
+		}
+	}
+}
+
+static void cl_temperature_recovery_comp(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	s8 power_offset = cl_hw->temp_comp_db.power_offset;
+
+	if (!chip->conf->ce_temp_comp_en)
+		return;
+
+	if (power_offset)
+		cl_temperature_set_power_offset(cl_hw, power_offset);
+}
+
+void cl_temperature_init(struct cl_chip *chip)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	struct cl_temp_protect_db *temp_protect_db = &temperature->protect_db;
+	unsigned long curr_time_ms = jiffies_to_msecs(jiffies);
+
+	init_waitqueue_head(&temperature->wait_done);
+	init_waitqueue_head(&temperature->measurement_done);
+
+	mutex_init(&temperature->mutex);
+	mutex_init(&temperature->hw_lock);
+
+	temperature->internal_last = UNCALIBRATED_TEMPERATURE;
+	temperature->internal_read_timestamp = curr_time_ms;
+	temperature->external_last = UNCALIBRATED_TEMPERATURE;
+	temperature->external_read_timestamp = curr_time_ms;
+
+	/* Temp_protect_db init */
+	temp_protect_db->duty_cycle = DUTY_CYCLE_MAX;
+	temp_protect_db->test_mode_duty_cycle = DUTY_CYCLE_MAX;
+	temp_protect_db->last_timestamp = curr_time_ms;
+
+	temperature->kthread = kthread_run(cl_temperature_kthread,
+					   chip,
+					   "cl_temperature_kthread_%u",
+					   chip->idx);
+	if (IS_ERR(temperature->kthread)) {
+		cl_dbg_chip_err(chip, "Failed to create temperature kthread\n");
+		temperature->kthread = NULL;
+	}
+}
+
+void cl_temperature_close(struct cl_chip *chip)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (temperature->kthread) {
+		cl_dbg_chip_trace(chip, "stopping temperature kthread\n");
+		if (kthread_stop(temperature->kthread) != -EINTR)
+			wake_up(&temperature->wait_done);
+
+		temperature->kthread = NULL;
+	}
+}
+
+s8 cl_temperature_read(struct cl_hw *cl_hw, enum cl_temp_mode mode)
+{
+	u16 raw_bits = 0;
+	s16 temp_val = 0;
+	unsigned long curr_time = jiffies_to_msecs(jiffies);
+	unsigned long diff_time = 0;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (!IS_REAL_PHY(chip))
+		return UNCALIBRATED_TEMPERATURE;
+
+	mutex_lock(&temperature->mutex);
+
+	switch (mode) {
+	case TEMP_MODE_INTERNAL:
+		diff_time = curr_time - temperature->internal_read_timestamp;
+		if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+			temp_val = temperature->internal_last;
+			cl_dbg_chip_trace(chip, "Return last internal temperature %d\n", temp_val);
+			goto read_out;
+		}
+		break;
+	case TEMP_MODE_EXTERNAL:
+		diff_time = curr_time - temperature->external_read_timestamp;
+		if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+			temp_val = temperature->external_last;
+			cl_dbg_chip_trace(chip, "Return last external temperature %d\n", temp_val);
+			goto read_out;
+		}
+		break;
+	default:
+		cl_dbg_chip_err(chip, "Invalid temperature mode %d\n", mode);
+		goto read_err;
+	}
+
+	if (cl_temperature_read_fw(cl_hw, mode, &raw_bits)) {
+		cl_dbg_chip_err(chip, "Temperature read failed\n");
+		goto read_err;
+	}
+
+	temp_val = cl_raw_bits_to_temperature(raw_bits, mode);
+
+	if (temp_val > TEMPERATURE_MAX || temp_val < TEMPERATURE_MIN) {
+		cl_dbg_chip_err(chip, "Invalid temperature value %d\n", temp_val);
+		goto read_err;
+	}
+
+	/* Update temperature read db */
+	if (mode == TEMP_MODE_INTERNAL) {
+		temperature->internal_last = temp_val;
+		temperature->internal_read_timestamp = jiffies_to_msecs(jiffies);
+		cl_dbg_chip_trace(chip, "Read and save internal temperature %d\n", temp_val);
+	} else {
+		temperature->external_last = temp_val;
+		temperature->external_read_timestamp = jiffies_to_msecs(jiffies);
+		cl_dbg_chip_trace(chip, "Read and save external temperature %d\n", temp_val);
+	}
+
+read_out:
+	mutex_unlock(&temperature->mutex);
+	return temp_val;
+
+read_err:
+	/* If temperature read failed return the last valid value */
+	mutex_unlock(&temperature->mutex);
+
+	return (mode == TEMP_MODE_INTERNAL) ?
+		temperature->internal_last : temperature->external_last;
+}
+
+void cl_temperature_recovery(struct cl_hw *cl_hw)
+{
+	cl_temperature_recovery_protect(cl_hw);
+	cl_temperature_recovery_comp(cl_hw);
+}
+
+int cl_temperature_diff_e2p_read(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (cl_e2p_read_temp_diff(chip, &temperature->diff_internal_external) ||
+	    temperature->diff_internal_external == TEMP_DIFF_INVALID) {
+		if (cl_temperature_diff_update(cl_hw))
+			return -1;
+
+		cl_dbg_chip_verbose(chip, "Temperature difference: Internal - External = %d\n",
+				    temperature->diff_internal_external);
+	}
+
+	return 0;
+}
+
+s16 cl_temperature_calib_calc(struct cl_hw *cl_hw, u16 raw_bits)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	s16 temperature = cl_raw_bits_to_temperature(raw_bits, TEMP_MODE_INTERNAL) +
+		chip->conf->ce_temp_protect_delta;
+
+	if (temperature >= TEMPERATURE_MIN && temperature <= TEMPERATURE_MAX)
+		return temperature;
+
+	cl_dbg_chip_err(chip, "Invalid temperature = %d\n", temperature);
+
+	return (chip->temperature.internal_last + chip->conf->ce_temp_protect_delta);
+}
+
+void cl_temperature_comp_update_calib(struct cl_hw *cl_hw)
+{
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	u8 ant, ant_cnt = 0;
+	s16 total_temp = 0;
+	struct cl_tx_power_info *info = NULL;
+
+	if (unlikely(chan_idx == INVALID_CHAN_IDX)) {
+		cl_dbg_err(cl_hw, "Unsupported frequency %u\n", cl_hw->center_freq);
+		return;
+	}
+
+	info = &cl_hw->tx_pow_info[chan_idx][0];
+
+	/* Sum up the temperature of all phys */
+	for (ant = 0; ant < MAX_ANTENNAS && ant_cnt < cl_hw->num_antennas; ant++) {
+		if (!(cl_hw->mask_num_antennas & BIT(ant)))
+			continue;
+
+		total_temp += info[ant].temperature;
+		ant_cnt++;
+	}
+
+	/* Average the total temperature and update chan_params */
+	cl_hw->temp_comp_db.calib_temperature = DIV_ROUND_CLOSEST(total_temp, cl_hw->num_antennas);
+}
+
-- 
2.36.1


  parent reply	other threads:[~2022-05-24 11:40 UTC|newest]

Thread overview: 125+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
2022-05-24 11:33 ` [RFC v2 02/96] celeno: add Makefile viktor.barna
2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
2022-05-26 18:18   ` Johannes Berg
2022-05-27  6:09     ` Kalle Valo
2022-07-11 23:04       ` Viktor Barna
2022-07-13  7:32   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
2022-05-26 18:24   ` Johannes Berg
2022-07-13  7:39   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
2022-05-26 18:19   ` Johannes Berg
2022-05-26 18:22   ` Johannes Berg
2022-05-24 11:33 ` [RFC v2 06/96] cl8k: add ampdu.h viktor.barna
2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
2022-05-24 17:24   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 08/96] cl8k: add bf.h viktor.barna
2022-05-24 11:33 ` [RFC v2 09/96] cl8k: add calib.c viktor.barna
2022-05-24 11:33 ` [RFC v2 10/96] cl8k: add calib.h viktor.barna
2022-05-24 11:33 ` [RFC v2 11/96] cl8k: add channel.c viktor.barna
2022-05-24 11:33 ` [RFC v2 12/96] cl8k: add channel.h viktor.barna
2022-05-24 11:33 ` [RFC v2 13/96] cl8k: add chip.c viktor.barna
2022-05-24 11:33 ` [RFC v2 14/96] cl8k: add chip.h viktor.barna
2022-05-24 11:33 ` [RFC v2 15/96] cl8k: add config.c viktor.barna
2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
2022-05-25 18:31   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 17/96] cl8k: add debug.c viktor.barna
2022-05-24 11:33 ` [RFC v2 18/96] cl8k: add debug.h viktor.barna
2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
2022-05-25 18:39   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 20/96] cl8k: add dfs.c viktor.barna
2022-05-24 11:33 ` [RFC v2 21/96] cl8k: add dfs.h viktor.barna
2022-05-24 11:33 ` [RFC v2 22/96] cl8k: add dsp.c viktor.barna
2022-05-24 11:33 ` [RFC v2 23/96] cl8k: add dsp.h viktor.barna
2022-05-24 11:33 ` [RFC v2 24/96] cl8k: add e2p.c viktor.barna
2022-05-24 11:33 ` [RFC v2 25/96] cl8k: add e2p.h viktor.barna
2022-05-24 11:33 ` [RFC v2 26/96] cl8k: add eeprom.h viktor.barna
2022-05-24 11:33 ` [RFC v2 27/96] cl8k: add ela.c viktor.barna
2022-05-24 11:33 ` [RFC v2 28/96] cl8k: add ela.h viktor.barna
2022-05-24 11:33 ` [RFC v2 29/96] cl8k: add enhanced_tim.c viktor.barna
2022-05-24 11:33 ` [RFC v2 30/96] cl8k: add enhanced_tim.h viktor.barna
2022-05-24 11:33 ` [RFC v2 31/96] cl8k: add fw.c viktor.barna
2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
2022-05-25 18:58   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 33/96] cl8k: add hw.c viktor.barna
2022-05-24 11:34 ` [RFC v2 34/96] cl8k: add hw.h viktor.barna
2022-05-24 11:34 ` [RFC v2 35/96] cl8k: add ipc_shared.h viktor.barna
2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
2022-05-26 19:38   ` Johannes Berg
2022-07-11 23:10     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 37/96] cl8k: add key.h viktor.barna
2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
2022-05-26 19:49   ` Johannes Berg
2022-07-11 23:13     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
2022-05-26 19:52   ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
2022-05-26 22:31   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 41/96] cl8k: add mac_addr.h viktor.barna
2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
2022-05-26 23:01   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 43/96] cl8k: add main.h viktor.barna
2022-05-24 11:34 ` [RFC v2 44/96] cl8k: add maintenance.c viktor.barna
2022-05-24 11:34 ` [RFC v2 45/96] cl8k: add maintenance.h viktor.barna
2022-05-24 11:34 ` [RFC v2 46/96] cl8k: add motion_sense.c viktor.barna
2022-05-24 11:34 ` [RFC v2 47/96] cl8k: add motion_sense.h viktor.barna
2022-05-24 11:34 ` [RFC v2 48/96] cl8k: add pci.c viktor.barna
2022-05-24 11:34 ` [RFC v2 49/96] cl8k: add pci.h viktor.barna
2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
2022-06-01  0:27   ` Jeff Johnson
2022-07-11 23:16     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 51/96] cl8k: add phy.h viktor.barna
2022-05-24 11:34 ` [RFC v2 52/96] cl8k: add platform.c viktor.barna
2022-05-24 11:34 ` [RFC v2 53/96] cl8k: add platform.h viktor.barna
2022-05-24 11:34 ` [RFC v2 54/96] cl8k: add power.c viktor.barna
2022-05-24 11:34 ` [RFC v2 55/96] cl8k: add power.h viktor.barna
2022-05-24 11:34 ` [RFC v2 56/96] cl8k: add radio.c viktor.barna
2022-05-24 11:34 ` [RFC v2 57/96] cl8k: add radio.h viktor.barna
2022-05-24 11:34 ` [RFC v2 58/96] cl8k: add rates.c viktor.barna
2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
2022-05-26 19:54   ` Johannes Berg
2022-07-11 23:17     ` Viktor Barna
2022-07-12  7:17       ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 60/96] cl8k: add recovery.c viktor.barna
2022-05-24 11:34 ` [RFC v2 61/96] cl8k: add recovery.h viktor.barna
2022-05-24 11:34 ` [RFC v2 62/96] cl8k: add regdom.c viktor.barna
2022-05-24 11:34 ` [RFC v2 63/96] cl8k: add regdom.h viktor.barna
2022-05-24 11:34 ` [RFC v2 64/96] cl8k: add reg/reg_access.h viktor.barna
2022-05-24 11:34 ` [RFC v2 65/96] cl8k: add reg/reg_defs.h viktor.barna
2022-05-24 11:34 ` [RFC v2 66/96] cl8k: add rfic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
2022-06-02 20:40   ` Jeff Johnson
2022-07-11 23:18     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 68/96] cl8k: add rx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 69/96] cl8k: add rx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 70/96] cl8k: add scan.c viktor.barna
2022-05-24 11:34 ` [RFC v2 71/96] cl8k: add scan.h viktor.barna
2022-05-24 11:34 ` [RFC v2 72/96] cl8k: add sounding.c viktor.barna
2022-05-24 11:34 ` [RFC v2 73/96] cl8k: add sounding.h viktor.barna
2022-05-24 11:34 ` [RFC v2 74/96] cl8k: add sta.c viktor.barna
2022-05-24 11:34 ` [RFC v2 75/96] cl8k: add sta.h viktor.barna
2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
2022-06-02 20:59   ` Jeff Johnson
2022-07-11 23:20     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 77/96] cl8k: add stats.h viktor.barna
2022-05-24 11:34 ` [RFC v2 78/96] cl8k: add tcv.c viktor.barna
2022-05-24 11:34 ` [RFC v2 79/96] cl8k: add tcv.h viktor.barna
2022-05-24 11:34 ` viktor.barna [this message]
2022-05-24 11:34 ` [RFC v2 81/96] cl8k: add temperature.h viktor.barna
2022-05-24 11:34 ` [RFC v2 82/96] cl8k: add traffic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 83/96] cl8k: add traffic.h viktor.barna
2022-05-24 11:34 ` [RFC v2 84/96] cl8k: add tx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 85/96] cl8k: add tx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 86/96] cl8k: add utils.c viktor.barna
2022-05-24 11:34 ` [RFC v2 87/96] cl8k: add utils.h viktor.barna
2022-05-24 11:34 ` [RFC v2 88/96] cl8k: add version.c viktor.barna
2022-05-24 11:34 ` [RFC v2 89/96] cl8k: add version.h viktor.barna
2022-05-24 11:34 ` [RFC v2 90/96] cl8k: add vif.c viktor.barna
2022-05-24 11:34 ` [RFC v2 91/96] cl8k: add vif.h viktor.barna
2022-05-24 11:34 ` [RFC v2 92/96] cl8k: add vns.c viktor.barna
2022-05-24 11:34 ` [RFC v2 93/96] cl8k: add vns.h viktor.barna
2022-05-24 11:35 ` [RFC v2 94/96] cl8k: add wrs.c viktor.barna
2022-05-24 11:35 ` [RFC v2 95/96] cl8k: add wrs.h viktor.barna
2022-05-24 11:35 ` [RFC v2 96/96] wireless: add Celeno vendor viktor.barna

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220524113502.1094459-81-viktor.barna@celeno.com \
    --to=viktor.barna@celeno.com \
    --cc=aviad.brikman@celeno.com \
    --cc=davem@davemloft.net \
    --cc=eliav.farber@gmail.com \
    --cc=kuba@kernel.org \
    --cc=kvalo@codeaurora.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=maksym.kokhan@celeno.com \
    --cc=oleksandr.savchenko@celeno.com \
    --cc=shay.bar@celeno.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).