drivers/mfd/mc13xxx-core.c

Source file repositories/reference/linux-study-clean/drivers/mfd/mc13xxx-core.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/mc13xxx-core.c
Extension
.c
Size
13306 bytes
Lines
514
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 mc13xxx_adcdone_data {
	struct mc13xxx *mc13xxx;
	struct completion done;
};

static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
{
	struct mc13xxx_adcdone_data *adcdone_data = data;

	complete_all(&adcdone_data->done);

	return IRQ_HANDLED;
}

#define MC13XXX_ADC_WORKING (1 << 0)

int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
		unsigned int channel, u8 ato, bool atox,
		unsigned int *sample)
{
	u32 adc0, adc1, old_adc0;
	int i, ret;
	struct mc13xxx_adcdone_data adcdone_data = {
		.mc13xxx = mc13xxx,
	};
	init_completion(&adcdone_data.done);

	dev_dbg(mc13xxx->dev, "%s\n", __func__);

	mc13xxx_lock(mc13xxx);

	if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) {
		ret = -EBUSY;
		goto out;
	}

	mc13xxx->adcflags |= MC13XXX_ADC_WORKING;

	ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
	if (ret)
		goto out;

	adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 |
	       MC13XXX_ADC0_CHRGRAWDIV;
	adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;

	/*
	 * Channels mapped through ADIN7:
	 * 7  - General purpose ADIN7
	 * 16 - UID
	 * 17 - Die temperature
	 */
	if (channel > 7 && channel < 16) {
		adc1 |= MC13XXX_ADC1_ADSEL;
	} else if (channel == 16) {
		adc0 |= MC13XXX_ADC0_ADIN7SEL_UID;
		channel = 7;
	} else if (channel == 17) {
		adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE;
		channel = 7;
	}

	switch (mode) {
	case MC13XXX_ADC_MODE_TS:
		adc0 |= MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 |
			MC13XXX_ADC0_TSMOD1;
		adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
		break;

	case MC13XXX_ADC_MODE_SINGLE_CHAN:
		adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
		adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
		adc1 |= MC13XXX_ADC1_RAND;
		break;

	case MC13XXX_ADC_MODE_MULT_CHAN:
		adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
		adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
		break;

	default:
		mc13xxx_unlock(mc13xxx);
		return -EINVAL;
	}

	adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
	if (atox)
		adc1 |= MC13783_ADC1_ATOX;

	dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);

Annotation

Implementation Notes