drivers/iio/adc/sophgo-cv1800b-adc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/sophgo-cv1800b-adc.c
Extension
.c
Size
6529 bytes
Lines
228
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 cv1800b_adc {
	struct completion completion;
	void __iomem *regs;
	struct mutex lock; /* ADC Control and Result register */
	struct clk *clk;
	int irq;
};

static const struct iio_chan_spec sophgo_channels[] = {
	CV1800B_ADC_CHANNEL(0),
	CV1800B_ADC_CHANNEL(1),
	CV1800B_ADC_CHANNEL(2),
};

static void cv1800b_adc_start_measurement(struct cv1800b_adc *saradc,
					  int channel)
{
	writel(0, saradc->regs + CV1800B_ADC_CTRL_REG);
	writel(CV1800B_ADC_SEL(channel) | CV1800B_ADC_EN,
	       saradc->regs + CV1800B_ADC_CTRL_REG);
}

static int cv1800b_adc_wait(struct cv1800b_adc *saradc)
{
	if (saradc->irq < 0) {
		u32 reg;

		return readl_poll_timeout(saradc->regs + CV1800B_ADC_STATUS_REG,
					  reg, !(reg & CV1800B_ADC_BUSY),
					  500, CV1800B_READ_TIMEOUT_US);
	}

	return wait_for_completion_timeout(&saradc->completion,
					   msecs_to_jiffies(CV1800B_READ_TIMEOUT_MS)) > 0 ?
					   0 : -ETIMEDOUT;
}

static int cv1800b_adc_read_raw(struct iio_dev *indio_dev,
				struct iio_chan_spec const *chan,
				int *val, int *val2, long mask)
{
	struct cv1800b_adc *saradc = iio_priv(indio_dev);

	switch (mask) {
	case IIO_CHAN_INFO_RAW: {
		u32 sample;

		scoped_guard(mutex, &saradc->lock) {
			int ret;

			cv1800b_adc_start_measurement(saradc, chan->scan_index);
			ret = cv1800b_adc_wait(saradc);
			if (ret < 0)
				return ret;

			sample = readl(saradc->regs + CV1800B_ADC_CH_RESULT_REG(chan->scan_index));
		}
		if (!(sample & CV1800B_ADC_CH_VALID))
			return -ENODATA;

		*val = sample & CV1800B_ADC_CH_RESULT;
		return IIO_VAL_INT;
	}
	case IIO_CHAN_INFO_SCALE:
		*val = 3300;
		*val2 = 12;
		return IIO_VAL_FRACTIONAL_LOG2;
	case IIO_CHAN_INFO_SAMP_FREQ: {
		u32 status_reg = readl(saradc->regs + CV1800B_ADC_CYC_SET_REG);
		unsigned int clk_div = (1 + FIELD_GET(CV1800B_MASK_CLKDIV, status_reg));
		unsigned int freq = clk_get_rate(saradc->clk) / clk_div;
		unsigned int nb_startup_cycle = 1 + FIELD_GET(CV1800B_MASK_STARTUP_CYCLE, status_reg);
		unsigned int nb_sample_cycle = 1 + FIELD_GET(CV1800B_MASK_SAMPLE_WINDOW, status_reg);
		unsigned int nb_compare_cycle = 1 + FIELD_GET(CV1800B_MASK_COMPARE_CYCLE, status_reg);

		*val = freq / (nb_startup_cycle + nb_sample_cycle + nb_compare_cycle);
		return IIO_VAL_INT;
	}
	default:
		return -EINVAL;
	}
}

static irqreturn_t cv1800b_adc_interrupt_handler(int irq, void *private)
{
	struct cv1800b_adc *saradc = private;
	u32 reg = readl(saradc->regs + CV1800B_ADC_INTR_STA_REG);

	if (!(FIELD_GET(CV1800B_ADC_INTR_STA_BIT, reg)))
		return IRQ_NONE;

Annotation

Implementation Notes