drivers/thermal/airoha_thermal.c

Source file repositories/reference/linux-study-clean/drivers/thermal/airoha_thermal.c

File Facts

System
Linux kernel
Corpus path
drivers/thermal/airoha_thermal.c
Extension
.c
Size
16451 bytes
Lines
490
Domain
Driver Families
Bucket
drivers/thermal
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct airoha_thermal_priv {
	void __iomem *base;
	struct regmap *chip_scu;
	struct resource scu_adc_res;

	struct thermal_zone_device *tz;
	int init_temp;
	int default_slope;
	int default_offset;
};

static int airoha_get_thermal_ADC(struct airoha_thermal_priv *priv)
{
	u32 val;

	regmap_read(priv->chip_scu, EN7581_DOUT_TADC, &val);
	return FIELD_GET(EN7581_DOUT_TADC_MASK, val);
}

static void airoha_init_thermal_ADC_mode(struct airoha_thermal_priv *priv)
{
	u32 adc_mux, pllrg;

	/* Save PLLRG current value */
	regmap_read(priv->chip_scu, EN7581_PLLRG_PROTECT, &pllrg);

	/* Give access to thermal regs */
	regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, EN7581_SCU_THERMAL_PROTECT_KEY);
	adc_mux = FIELD_PREP(EN7581_MUX_TADC, EN7581_SCU_THERMAL_MUX_DIODE1);
	regmap_write(priv->chip_scu, EN7581_PWD_TADC, adc_mux);

	/* Restore PLLRG value on exit */
	regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, pllrg);
}

static int airoha_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
	struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
	int min_value, max_value, avg_value, value;
	int i;

	avg_value = 0;
	min_value = INT_MAX;
	max_value = INT_MIN;

	for (i = 0; i < AIROHA_MAX_SAMPLES; i++) {
		value = airoha_get_thermal_ADC(priv);
		min_value = min(value, min_value);
		max_value = max(value, max_value);
		avg_value += value;
	}

	/* Drop min and max and average for the remaining sample */
	avg_value -= (min_value + max_value);
	avg_value /= AIROHA_MAX_SAMPLES - 2;

	*temp = RAW_TO_TEMP(priv, avg_value);
	return 0;
}

static int airoha_thermal_set_trips(struct thermal_zone_device *tz, int low,
				    int high)
{
	struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
	bool enable_monitor = false;

	if (high != INT_MAX) {
		/* Validate high and clamp it a supported value */
		high = clamp_t(int, high, RAW_TO_TEMP(priv, 0),
			       RAW_TO_TEMP(priv, FIELD_MAX(EN7581_DOUT_TADC_MASK)));

		/* We offset the high temp of 1°C to trigger correct event */
		writel(TEMP_TO_RAW(priv, high) >> 4,
		       priv->base + EN7581_TEMPOFFSETH);

		enable_monitor = true;
	}

	if (low != -INT_MAX) {
		/* Validate low and clamp it to a supported value */
		low = clamp_t(int, high, RAW_TO_TEMP(priv, 0),
			      RAW_TO_TEMP(priv, FIELD_MAX(EN7581_DOUT_TADC_MASK)));

		/* We offset the low temp of 1°C to trigger correct event */
		writel(TEMP_TO_RAW(priv, low) >> 4,
		       priv->base + EN7581_TEMPOFFSETL);

		enable_monitor = true;
	}

Annotation

Implementation Notes