drivers/thermal/renesas/rzg3s_thermal.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thermal/renesas/rzg3s_thermal.c
Extension
.c
Size
7039 bytes
Lines
273
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 rzg3s_thermal_priv {
	void __iomem *base;
	struct device *dev;
	struct thermal_zone_device *tz;
	struct reset_control *rstc;
	struct iio_channel *channel;
	enum thermal_device_mode mode;
	u16 calib0;
	u16 calib1;
};

static int rzg3s_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
	struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz);
	int ts_code_ave = 0;

	if (priv->mode != THERMAL_DEVICE_ENABLED)
		return -EAGAIN;

	for (u8 i = 0; i < TSU_READ_STEPS; i++) {
		int ret, val;

		ret = iio_read_channel_raw(priv->channel, &val);
		if (ret < 0)
			return ret;

		ts_code_ave += val;
		/*
		 * According to the HW manual (Rev.1.10, section 40.4.4 Procedure for Measuring
		 * the Temperature) we need to wait here at leat 3us.
		 */
		usleep_range(5, 10);
	}

	ts_code_ave = DIV_ROUND_CLOSEST(MCELSIUS(ts_code_ave), TSU_READ_STEPS);

	/*
	 * According to the HW manual (Rev.1.10, section 40.4.4 Procedure for Measuring the
	 * Temperature) the computation formula is as follows:
	 *
	 * Tj = (ts_code_ave - priv->calib1) * 165 / (priv->calib0 - priv->calib1) - 40
	 *
	 * Convert everything to milli Celsius before applying the formula to avoid
	 * losing precision.
	 */

	*temp = div_s64((s64)(ts_code_ave - MCELSIUS(priv->calib1)) * MCELSIUS(165),
			MCELSIUS(priv->calib0 - priv->calib1)) - MCELSIUS(40);

	/* Report it in milli degrees Celsius and round it up to 0.5 degrees Celsius. */
	*temp = roundup(*temp, 500);

	return 0;
}

static void rzg3s_thermal_set_mode(struct rzg3s_thermal_priv *priv,
				   enum thermal_device_mode mode)
{
	struct device *dev = priv->dev;
	int ret;

	ret = pm_runtime_resume_and_get(dev);
	if (ret)
		return;

	if (mode == THERMAL_DEVICE_DISABLED) {
		writel(0, priv->base + TSU_SM);
	} else {
		writel(TSU_SM_EN, priv->base + TSU_SM);
		/*
		 * According to the HW manual (Rev.1.10, section 40.4.1 Procedure for
		 * Starting the TSU) we need to wait here 30us or more.
		 */
		usleep_range(30, 40);

		writel(TSU_SM_OE | TSU_SM_EN, priv->base + TSU_SM);
		/*
		 * According to the HW manual (Rev.1.10, section 40.4.1 Procedure for
		 * Starting the TSU) we need to wait here 50us or more.
		 */
		usleep_range(50, 60);
	}

	pm_runtime_put_autosuspend(dev);
}

static int rzg3s_thermal_change_mode(struct thermal_zone_device *tz,
				     enum thermal_device_mode mode)
{
	struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz);

Annotation

Implementation Notes