drivers/thermal/renesas/rzg2l_thermal.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thermal/renesas/rzg2l_thermal.c
Extension
.c
Size
6663 bytes
Lines
250
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 rzg2l_thermal_priv {
	struct device *dev;
	void __iomem *base;
	struct thermal_zone_device *zone;
	struct reset_control *rstc;
	u32 calib0, calib1;
};

static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv, u32 reg)
{
	return ioread32(priv->base + reg);
}

static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv, u32 reg,
				       u32 data)
{
	iowrite32(data, priv->base + reg);
}

static int rzg2l_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
	struct rzg2l_thermal_priv *priv = thermal_zone_device_priv(tz);
	u32 result = 0, dsensor, ts_code_ave;
	int val, i;

	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
		/*
		 * TSU repeats measurement at 20 microseconds intervals and
		 * automatically updates the results of measurement. As per
		 * the HW manual for measuring temperature we need to read 8
		 * values consecutively and then take the average.
		 * ts_code_ave = (ts_code[0] + ⋯ + ts_code[7]) / 8
		 */
		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
		usleep_range(20, 30);
	}

	ts_code_ave = result / TS_CODE_CAP_TIMES;

	/*
	 * Calculate actual sensor value by applying curvature correction formula
	 * dsensor = ts_code_ave / (1 + ts_code_ave * 0.000013). Here we are doing
	 * integer calculation by scaling all the values by 1000000.
	 */
	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * CURVATURE_CORRECTION_CONST));

	/*
	 * The temperature Tj is calculated by the formula
	 * Tj = (dsensor − calib1) * 165/ (calib0 − calib1) − 40
	 * where calib0 and calib1 are the calibration values.
	 */
	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
		(priv->calib0 - priv->calib1))) - MCELSIUS(40);

	*temp = roundup(val, RZG2L_THERMAL_GRAN);

	return 0;
}

static const struct thermal_zone_device_ops rzg2l_tz_of_ops = {
	.get_temp = rzg2l_thermal_get_temp,
};

static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv)
{
	u32 reg_val;

	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
	rzg2l_thermal_write(priv, TSU_ST, 0);

	/*
	 * Before setting the START bit, TSU should be in normal operating
	 * mode. As per the HW manual, it will take 60 µs to place the TSU
	 * into normal operating mode.
	 */
	usleep_range(60, 80);

	reg_val = rzg2l_thermal_read(priv, TSU_ST);
	reg_val |= TSU_ST_START;
	rzg2l_thermal_write(priv, TSU_ST, reg_val);

	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
				  reg_val == TSU_SS_CONV_RUNNING, 50,
				  RZG2L_TSU_SS_TIMEOUT_US);
}

static void rzg2l_thermal_reset_assert_pm_disable_put(struct platform_device *pdev)
{
	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);

Annotation

Implementation Notes