int pcap_adc_async(struct pcap_chip *pcap, u8 bank, u32 flags, u8 ch[], void *callback, void *data) { struct pcap_adc_request *req; /* This will be freed after we have a result */ req = kmalloc(sizeof(struct pcap_adc_request), GFP_KERNEL); if (!req) return -ENOMEM; req->bank = bank; req->flags = flags; req->ch[0] = ch[0]; req->ch[1] = ch[1]; req->callback = callback; req->data = data; mutex_lock(&pcap->adc_mutex); if (pcap->adc_queue[pcap->adc_tail]) { mutex_unlock(&pcap->adc_mutex); kfree(req); return -EBUSY; } pcap->adc_queue[pcap->adc_tail] = req; pcap->adc_tail = (pcap->adc_tail + 1) & (PCAP_ADC_MAXQ - 1); mutex_unlock(&pcap->adc_mutex); /* start conversion */ pcap_adc_trigger(pcap); return 0; }
static irqreturn_t pcap_adc_irq(int irq, void *_pcap) { struct pcap_chip *pcap = _pcap; struct pcap_adc_request *req; u16 res[2]; u32 tmp; mutex_lock(&pcap->adc_mutex); req = pcap->adc_queue[pcap->adc_head]; if (WARN(!req, "adc irq without pending request\n")) { mutex_unlock(&pcap->adc_mutex); return IRQ_HANDLED; } /* read requested channels results */ ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); tmp &= ~(PCAP_ADC_ADA1_MASK | PCAP_ADC_ADA2_MASK); tmp |= (req->ch[0] << PCAP_ADC_ADA1_SHIFT); tmp |= (req->ch[1] << PCAP_ADC_ADA2_SHIFT); ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); ezx_pcap_read(pcap, PCAP_REG_ADR, &tmp); res[0] = (tmp & PCAP_ADR_ADD1_MASK) >> PCAP_ADR_ADD1_SHIFT; res[1] = (tmp & PCAP_ADR_ADD2_MASK) >> PCAP_ADR_ADD2_SHIFT; pcap->adc_queue[pcap->adc_head] = NULL; pcap->adc_head = (pcap->adc_head + 1) & (PCAP_ADC_MAXQ - 1); mutex_unlock(&pcap->adc_mutex); /* pass the results and release memory */ req->callback(req->data, res); kfree(req); /* trigger next conversion (if any) on queue */ pcap_adc_trigger(pcap); return IRQ_HANDLED; }
static irqreturn_t pcap_adc_irq(int irq, void *_pcap) { struct pcap_chip *pcap = _pcap; struct pcap_adc_request *req; u16 res[2]; u32 tmp; mutex_lock(&pcap->adc_mutex); req = pcap->adc_queue[pcap->adc_head]; if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) { mutex_unlock(&pcap->adc_mutex); return IRQ_HANDLED; } ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); tmp &= ~(PCAP_ADC_ADA1_MASK | PCAP_ADC_ADA2_MASK); tmp |= (req->ch[0] << PCAP_ADC_ADA1_SHIFT); tmp |= (req->ch[1] << PCAP_ADC_ADA2_SHIFT); ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); ezx_pcap_read(pcap, PCAP_REG_ADR, &tmp); res[0] = (tmp & PCAP_ADR_ADD1_MASK) >> PCAP_ADR_ADD1_SHIFT; res[1] = (tmp & PCAP_ADR_ADD2_MASK) >> PCAP_ADR_ADD2_SHIFT; pcap->adc_queue[pcap->adc_head] = NULL; pcap->adc_head = (pcap->adc_head + 1) & (PCAP_ADC_MAXQ - 1); mutex_unlock(&pcap->adc_mutex); req->callback(req->data, res); kfree(req); pcap_adc_trigger(pcap); return IRQ_HANDLED; }