drivers/thermal/spacemit/k1_tsensor.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thermal/spacemit/k1_tsensor.c
Extension
.c
Size
7901 bytes
Lines
281
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 k1_tsensor_channel {
	struct k1_tsensor *ts;
	struct thermal_zone_device *tzd;
	int id;
};

struct k1_tsensor {
	void __iomem *base;
	struct k1_tsensor_channel ch[MAX_SENSOR_NUMBER];
};

static void k1_tsensor_init(struct k1_tsensor *ts)
{
	u32 val;

	/* Disable all the interrupts */
	writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG);

	/* Configure ADC sampling time and filter period */
	val = readl(ts->base + K1_TSENSOR_TIME_REG);
	val &= ~K1_TSENSOR_TIME_MASK;
	val |= K1_TSENSOR_TIME_FILTER_PERIOD |
	       K1_TSENSOR_TIME_ADC_CNT_RST |
	       K1_TSENSOR_TIME_WAIT_REF_CNT;
	writel(val, ts->base + K1_TSENSOR_TIME_REG);

	/*
	 * Enable all sensors' auto mode, enable dither control,
	 * consecutive mode, and power up sensor.
	 */
	val = readl(ts->base + K1_TSENSOR_PCTRL_REG);
	val &= ~K1_TSENSOR_PCTRL_SW_CTRL;
	val &= ~K1_TSENSOR_PCTRL_CTUNE;
	val |= K1_TSENSOR_PCTRL_RAW_SEL |
	       K1_TSENSOR_PCTRL_TEMP_MODE |
	       K1_TSENSOR_PCTRL_HW_AUTO_MODE |
	       K1_TSENSOR_PCTRL_ENABLE;
	writel(val, ts->base + K1_TSENSOR_PCTRL_REG);

	/* Enable each sensor */
	val = readl(ts->base + K1_TSENSOR_EN_REG);
	val |= K1_TSENSOR_EN_ALL;
	writel(val, ts->base + K1_TSENSOR_EN_REG);
}

static void k1_tsensor_enable_irq(struct k1_tsensor_channel *ch)
{
	struct k1_tsensor *ts = ch->ts;
	u32 val;

	val = readl(ts->base + K1_TSENSOR_INT_CLR_REG);
	val |= K1_TSENSOR_INT_MASK(ch->id);
	writel(val, ts->base + K1_TSENSOR_INT_CLR_REG);

	val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
	val &= ~K1_TSENSOR_INT_MASK(ch->id);
	writel(val, ts->base + K1_TSENSOR_INT_EN_REG);

	/* Enable thermal interrupt */
	val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
	val |= K1_TSENSOR_INT_EN_MASK;
	writel(val, ts->base + K1_TSENSOR_INT_EN_REG);
}

/*
 * The conversion formula used is:
 * T(m°C) = (((raw_value & mask) >> shift) - TEMPERATURE_OFFSET) * 1000
 */
static int k1_tsensor_get_temp(struct thermal_zone_device *tz, int *temp)
{
	struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz);
	struct k1_tsensor *ts = ch->ts;
	u32 val;

	val = readl(ts->base + K1_TSENSOR_DATA_REG(ch->id));
	if (ch->id % 2)
		*temp = FIELD_GET(K1_TSENSOR_DATA_HIGH_MASK, val);
	else
		*temp = FIELD_GET(K1_TSENSOR_DATA_LOW_MASK, val);

	*temp -= TEMPERATURE_OFFSET;
	*temp *= 1000;

	return 0;
}

/*
 * For each sensor, the hardware threshold register is 32 bits:
 * - Lower 16 bits [15:0] configure the low threshold temperature.
 * - Upper 16 bits [31:16] configure the high threshold temperature.

Annotation

Implementation Notes