drivers/comedi/drivers/mpc624.c

Source file repositories/reference/linux-study-clean/drivers/comedi/drivers/mpc624.c

File Facts

System
Linux kernel
Corpus path
drivers/comedi/drivers/mpc624.c
Extension
.c
Size
8090 bytes
Lines
312
Domain
Driver Families
Bucket
drivers/comedi
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 mpc624_private {
	unsigned int ai_speed;
};

/* -------------------------------------------------------------------------- */
static const struct comedi_lrange range_mpc624_bipolar1 = {
	1,
	{
/* BIP_RANGE(1.01)  this is correct, */
	 /*  but my MPC-624 actually seems to have a range of 2.02 */
	 BIP_RANGE(2.02)
	}
};

static const struct comedi_lrange range_mpc624_bipolar10 = {
	1,
	{
/* BIP_RANGE(10.1)   this is correct, */
	 /*  but my MPC-624 actually seems to have a range of 20.2 */
	 BIP_RANGE(20.2)
	}
};

static unsigned int mpc624_ai_get_sample(struct comedi_device *dev,
					 struct comedi_subdevice *s)
{
	struct mpc624_private *devpriv = dev->private;
	unsigned int data_out = devpriv->ai_speed;
	unsigned int data_in = 0;
	unsigned int bit;
	int i;

	/* Start reading data */
	udelay(1);
	for (i = 0; i < 32; i++) {
		/* Set the clock low */
		outb(0, dev->iobase + MPC624_ADC);
		udelay(1);

		/* Set the ADSDI line for the next bit (send to MPC624) */
		bit = (data_out & BIT(31)) ? MPC624_ADSDI : 0;
		outb(bit, dev->iobase + MPC624_ADC);
		udelay(1);

		/* Set the clock high */
		outb(MPC624_ADSCK | bit, dev->iobase + MPC624_ADC);
		udelay(1);

		/* Read ADSDO on high clock (receive from MPC624) */
		data_in <<= 1;
		data_in |= (inb(dev->iobase + MPC624_ADC) & MPC624_ADSDO) >> 4;
		udelay(1);

		data_out <<= 1;
	}

	/*
	 * Received 32-bit long value consist of:
	 *	31: EOC - (End Of Transmission) bit - should be 0
	 *	30: DMY - (Dummy) bit - should be 0
	 *	29: SIG - (Sign) bit - 1 if positive, 0 if negative
	 *	28: MSB - (Most Significant Bit) - the first bit of the
	 *					   conversion result
	 *	....
	 *	05: LSB - (Least Significant Bit)- the last bit of the
	 *					   conversion result
	 *	04-00: sub-LSB - sub-LSBs are basically noise, but when
	 *			 averaged properly, they can increase
	 *			 conversion precision up to 29 bits;
	 *			 they can be discarded without loss of
	 *			 resolution.
	 */
	if (data_in & MPC624_EOC_BIT)
		dev_dbg(dev->class_dev, "EOC bit is set!");
	if (data_in & MPC624_DMY_BIT)
		dev_dbg(dev->class_dev, "DMY bit is set!");

	if (data_in & MPC624_SGN_BIT) {
		/*
		 * Voltage is positive
		 *
		 * comedi operates on unsigned numbers, so mask off EOC
		 * and DMY and don't clear the SGN bit
		 */
		data_in &= 0x3fffffff;
	} else {
		/*
		 * The voltage is negative
		 *
		 * data_in contains a number in 30-bit two's complement

Annotation

Implementation Notes