drivers/iio/adc/envelope-detector.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/envelope-detector.c
Extension
.c
Size
10778 bytes
Lines
409
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 envelope {
	spinlock_t comp_lock; /* protects comp */
	int comp;

	struct mutex read_lock; /* protects everything else */

	int comp_irq;
	u32 comp_irq_trigger;
	u32 comp_irq_trigger_inv;

	struct iio_channel *dac;
	struct delayed_work comp_timeout;

	unsigned int comp_interval;
	bool invert;
	u32 dac_max;

	int high;
	int level;
	int low;

	struct completion done;
};

/*
 * The envelope_detector_comp_latch function works together with the compare
 * interrupt service routine below (envelope_detector_comp_isr) as a latch
 * (one-bit memory) for if the interrupt has triggered since last calling
 * this function.
 * The ..._comp_isr function disables the interrupt so that the cpu does not
 * need to service a possible interrupt flood from the comparator when no-one
 * cares anyway, and this ..._comp_latch function reenables them again if
 * needed.
 */
static int envelope_detector_comp_latch(struct envelope *env)
{
	int comp;

	spin_lock_irq(&env->comp_lock);
	comp = env->comp;
	env->comp = 0;
	spin_unlock_irq(&env->comp_lock);

	if (!comp)
		return 0;

	/*
	 * The irq was disabled, and is reenabled just now.
	 * But there might have been a pending irq that
	 * happened while the irq was disabled that fires
	 * just as the irq is reenabled. That is not what
	 * is desired.
	 */
	enable_irq(env->comp_irq);

	/* So, synchronize this possibly pending irq... */
	synchronize_irq(env->comp_irq);

	/* ...and redo the whole dance. */
	spin_lock_irq(&env->comp_lock);
	comp = env->comp;
	env->comp = 0;
	spin_unlock_irq(&env->comp_lock);

	if (comp)
		enable_irq(env->comp_irq);

	return 1;
}

static irqreturn_t envelope_detector_comp_isr(int irq, void *ctx)
{
	struct envelope *env = ctx;

	spin_lock(&env->comp_lock);
	env->comp = 1;
	disable_irq_nosync(env->comp_irq);
	spin_unlock(&env->comp_lock);

	return IRQ_HANDLED;
}

static void envelope_detector_setup_compare(struct envelope *env)
{
	int ret;

	/*
	 * Do a binary search for the peak input level, and stop
	 * when that level is "trapped" between two adjacent DAC
	 * values.

Annotation

Implementation Notes