drivers/thermal/k3_bandgap.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thermal/k3_bandgap.c
Extension
.c
Size
8364 bytes
Lines
265
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 k3_bandgap {
	void __iomem *base;
};

/* common data structures */
struct k3_thermal_data {
	struct thermal_zone_device *tzd;
	struct k3_bandgap *bgp;
	int sensor_id;
	u32 ctrl_offset;
	u32 stat_offset;
};

static unsigned int vtm_get_best_value(unsigned int s0, unsigned int s1,
				       unsigned int s2)
{
	int d01 = abs(s0 - s1);
	int d02 = abs(s0 - s2);
	int d12 = abs(s1 - s2);

	if (d01 <= d02 && d01 <= d12)
		return (s0 + s1) / 2;

	if (d02 <= d01 && d02 <= d12)
		return (s0 + s2) / 2;

	return (s1 + s2) / 2;
}

static int k3_bgp_read_temp(struct k3_thermal_data *devdata,
			    int *temp)
{
	struct k3_bandgap *bgp;
	unsigned int dtemp, s0, s1, s2;

	bgp = devdata->bgp;

	/*
	 * Errata is applicable for am654 pg 1.0 silicon. There
	 * is a variation of the order for 8-10 degree centigrade.
	 * Work around that by getting the average of two closest
	 * readings out of three readings everytime we want to
	 * report temperatures.
	 *
	 * Errata workaround.
	 */
	s0 = readl(bgp->base + devdata->stat_offset) &
		K3_VTM_TS_STAT_DTEMP_MASK;
	s1 = readl(bgp->base + devdata->stat_offset) &
		K3_VTM_TS_STAT_DTEMP_MASK;
	s2 = readl(bgp->base + devdata->stat_offset) &
		K3_VTM_TS_STAT_DTEMP_MASK;
	dtemp = vtm_get_best_value(s0, s1, s2);

	if (dtemp < K3_VTM_ADC_BEGIN_VAL || dtemp > K3_VTM_ADC_END_VAL)
		return -EINVAL;

	*temp = k3_adc_to_temp[dtemp - K3_VTM_ADC_BEGIN_VAL];

	return 0;
}

static int k3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
	struct k3_thermal_data *data = thermal_zone_device_priv(tz);
	int ret = 0;

	ret = k3_bgp_read_temp(data, temp);
	if (ret)
		return ret;

	return ret;
}

static const struct thermal_zone_device_ops k3_of_thermal_ops = {
	.get_temp = k3_thermal_get_temp,
};

static const struct of_device_id of_k3_bandgap_match[];

static int k3_bandgap_probe(struct platform_device *pdev)
{
	int ret = 0, cnt, val, id;
	struct resource *res;
	struct device *dev = &pdev->dev;
	struct k3_bandgap *bgp;
	struct k3_thermal_data *data;

	if (ARRAY_SIZE(k3_adc_to_temp) != (K3_VTM_ADC_END_VAL + 1 -
						K3_VTM_ADC_BEGIN_VAL))

Annotation

Implementation Notes