drivers/thermal/loongson2_thermal.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thermal/loongson2_thermal.c
Extension
.c
Size
6066 bytes
Lines
219
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 loongson2_thermal_chip_data {
	unsigned int thermal_sensor_sel;
	unsigned int flags;
};

struct loongson2_thermal_data {
	void __iomem *ctrl_reg;
	void __iomem *temp_reg;
	const struct loongson2_thermal_chip_data *chip_data;
};

static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data,
				    int ctrl_data, bool low, bool enable)
{
	int reg_ctrl = 0;
	int reg_off  = data->chip_data->thermal_sensor_sel * 2;
	int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;

	reg_ctrl = ctrl_data + HECTO;
	reg_ctrl |= enable ? 0x100 : 0;
	writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
}

static int loongson2_thermal_set(struct loongson2_thermal_data *data,
				 int low, int high, bool enable)
{
	/* Set low temperature threshold */
	loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable);

	/* Set high temperature threshold */
	loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable);

	return 0;
}

static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
{
	int val;
	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);

	val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG);
	*temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;

	return 0;
}

static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)
{
	int val;
	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);

	val = readl(data->temp_reg);
	*temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO;

	return 0;
}

static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
{
	struct thermal_zone_device *tzd = dev;
	struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd);

	writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);

	thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED);

	return IRQ_HANDLED;
}

static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
{
	struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);

	return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
}

static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
	.get_temp = loongson2_2k1000_get_temp,
	.set_trips = loongson2_thermal_set_trips,
};

static const struct thermal_zone_device_ops loongson2_2k2000_of_thermal_ops = {
	.get_temp = loongson2_2k2000_get_temp,
	.set_trips = loongson2_thermal_set_trips,
};

static int loongson2_thermal_probe(struct platform_device *pdev)
{
	const struct thermal_zone_device_ops *thermal_ops;
	struct device *dev = &pdev->dev;

Annotation

Implementation Notes