drivers/iio/adc/spear_adc.c

Source file repositories/reference/linux-study-clean/drivers/iio/adc/spear_adc.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/spear_adc.c
Extension
.c
Size
9169 bytes
Lines
365
Domain
Driver Families
Bucket
drivers/iio
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 adc_regs_spear3xx {
	u32 status;
	u32 average;
	u32 scan_rate;
	u32 clk;	/* Not avail for 1340 & 1310 */
	u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
	u32 ch_data[SPEAR_ADC_CHANNEL_NUM];
};

struct chan_data {
	u32 lsb;
	u32 msb;
};

struct adc_regs_spear6xx {
	u32 status;
	u32 pad[2];
	u32 clk;
	u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
	struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM];
	u32 scan_rate_lo;
	u32 scan_rate_hi;
	struct chan_data average;
};

struct spear_adc_state {
	struct device *dev;
	struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
	struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
	struct clk *clk;
	struct completion completion;
	/*
	 * Lock to protect the device state during a potential concurrent
	 * read access from userspace. Reading a raw value requires a sequence
	 * of register writes, then a wait for a completion callback,
	 * and finally a register read, during which userspace could issue
	 * another read request. This lock protects a read access from
	 * occurring before another one has finished.
	 */
	struct mutex lock;
	u32 current_clk;
	u32 sampling_freq;
	u32 avg_samples;
	u32 vref_external;
	u32 value;
};

/*
 * Functions to access some SPEAr ADC register. Abstracted into
 * static inline functions, because of different register offsets
 * on different SoC variants (SPEAr300 vs SPEAr600 etc).
 */
static void spear_adc_set_status(struct spear_adc_state *st, u32 val)
{
	__raw_writel(val, &st->adc_base_spear6xx->status);
}

static void spear_adc_set_clk(struct spear_adc_state *st, u32 val)
{
	u32 clk_high, clk_low, count;
	u32 apb_clk = clk_get_rate(st->clk);

	count = DIV_ROUND_UP(apb_clk, val);
	clk_low = count / 2;
	clk_high = count - clk_low;
	st->current_clk = apb_clk / count;

	__raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high),
		     &st->adc_base_spear6xx->clk);
}

static void spear_adc_set_ctrl(struct spear_adc_state *st, int n,
			       u32 val)
{
	__raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]);
}

static u32 spear_adc_get_average(struct spear_adc_state *st)
{
	if (device_is_compatible(st->dev, "st,spear600-adc")) {
		return __raw_readl(&st->adc_base_spear6xx->average.msb) &
			SPEAR_ADC_DATA_MASK;
	} else {
		return __raw_readl(&st->adc_base_spear3xx->average) &
			SPEAR_ADC_DATA_MASK;
	}
}

static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate)
{

Annotation

Implementation Notes