All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.