drivers/iio/adc/rzn1-adc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/rzn1-adc.c
Extension
.c
Size
13826 bytes
Lines
491
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 rzn1_adc {
	struct device *dev;
	void __iomem *regs;
	struct mutex lock; /* ADC lock */
	int adc1_vref_mV; /* ADC1 Vref in mV. Negative if ADC1 is not used */
	int adc2_vref_mV; /* ADC2 Vref in mV. Negative if ADC2 is not used */
};

static int rzn1_adc_power(struct rzn1_adc *rzn1_adc, bool power)
{
	u32 v;

	writel(power ? 0 : RZN1_ADC_CONFIG_ADC_POWER_DOWN,
	       rzn1_adc->regs + RZN1_ADC_CONFIG_REG);

	/* Wait for the ADC_BUSY to clear */
	return readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_CONTROL_REG,
					 v, !(v & RZN1_ADC_CONTROL_ADC_BUSY),
					 0, 500);
}

static void rzn1_adc_vc_setup_conversion(struct rzn1_adc *rzn1_adc, u32 ch,
					 int adc1_ch, int adc2_ch)
{
	u32 vc = 0;

	if (adc1_ch != RZN1_ADC_NO_CHANNEL)
		vc |= RZN1_ADC_VC_ADC1_ENABLE |
		      FIELD_PREP(RZN1_ADC_VC_ADC1_CHANNEL_SEL_MASK, adc1_ch);

	if (adc2_ch != RZN1_ADC_NO_CHANNEL)
		vc |= RZN1_ADC_VC_ADC2_ENABLE |
		      FIELD_PREP(RZN1_ADC_VC_ADC2_CHANNEL_SEL_MASK, adc2_ch);

	writel(vc, rzn1_adc->regs + RZN1_ADC_VC_REG(ch));
}

static int rzn1_adc_vc_start_conversion(struct rzn1_adc *rzn1_adc, u32 ch)
{
	u32 val;

	val = readl(rzn1_adc->regs + RZN1_ADC_FORCE_REG);
	if (val & RZN1_ADC_FORCE_VC(ch))
		return -EBUSY;

	writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_SET_FORCE_REG);

	return 0;
}

static void rzn1_adc_vc_stop_conversion(struct rzn1_adc *rzn1_adc, u32 ch)
{
	writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_CLEAR_FORCE_REG);
}

static int rzn1_adc_vc_wait_conversion(struct rzn1_adc *rzn1_adc, u32 ch,
				       u32 *adc1_data, u32 *adc2_data)
{
	u32 data_reg;
	int ret;
	u32 v;

	/*
	 * When a VC is selected, it needs 20 ADC clocks to perform the
	 * conversion.
	 *
	 * The worst case is when the 16 VCs need to perform a conversion and
	 * our VC is the lowest in term of priority.
	 *
	 * In that case, the conversion is performed in 16 * 20 ADC clocks.
	 *
	 * The ADC clock can be set from 4MHz to 20MHz. This leads to a worst
	 * case of  16 * 20 * 1/4Mhz = 80us.
	 *
	 * Round it up to 100us.
	 */

	/* Wait for the ADC_FORCE_VC(n) to clear */
	ret = readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_FORCE_REG,
					v, !(v & RZN1_ADC_FORCE_VC(ch)),
					0, 100);
	if (ret)
		return ret;

	if (adc1_data) {
		data_reg = readl(rzn1_adc->regs + RZN1_ADC_ADC1_DATA_REG(ch));
		*adc1_data = FIELD_GET(RZN1_ADC_ADCX_DATA_DATA_MASK, data_reg);
	}

	if (adc2_data) {

Annotation

Implementation Notes