@@ -378,7 +378,6 @@ struct at91_adc_touch {
bool touching;
u16 x_pos;
unsigned long channels_bitmask;
- struct work_struct workq;
};
struct at91_adc_state {
@@ -405,6 +404,8 @@ struct at91_adc_state {
* sysfs.
*/
struct mutex lock;
+ struct work_struct workq;
+ s64 timestamp;
};
static const struct at91_adc_trigger at91_adc_trigger_list[] = {
@@ -710,7 +711,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio);
u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
- u8 bit;
/* clear TRGMOD */
status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
@@ -721,35 +721,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
/* set/unset hw trigger */
at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
- for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
- struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
-
- if (!chan)
- continue;
- /* these channel types cannot be handled by this trigger */
- if (chan->type == IIO_POSITIONRELATIVE ||
- chan->type == IIO_PRESSURE)
- continue;
-
- if (state) {
- at91_adc_writel(st, AT91_SAMA5D2_CHER,
- BIT(chan->channel));
- /* enable irq only if not using DMA */
- if (!st->dma_st.dma_chan) {
- at91_adc_writel(st, AT91_SAMA5D2_IER,
- BIT(chan->channel));
- }
- } else {
- /* disable irq only if not using DMA */
- if (!st->dma_st.dma_chan) {
- at91_adc_writel(st, AT91_SAMA5D2_IDR,
- BIT(chan->channel));
- }
- at91_adc_writel(st, AT91_SAMA5D2_CHDR,
- BIT(chan->channel));
- }
- }
-
return 0;
}
@@ -873,69 +844,90 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
return 0;
}
-static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
+#define AT91_ADC_BUFFER_CHECK_USE_IRQ(use_irq) { \
+ use_irq = true; \
+ /* if using DMA, we do not use our own IRQ (we use DMA-controller) */ \
+ if (st->dma_st.dma_chan) \
+ use_irq = false; \
+ /* if the trigger is not ours, then it has its own IRQ */ \
+ if (iio_trigger_validate_own_device(indio->trig, indio)) \
+ use_irq = false; \
+ }
+
+static int at91_adc_buffer_postenable(struct iio_dev *indio)
{
int ret;
- struct at91_adc_state *st = iio_priv(indio_dev);
+ u8 bit;
+ bool use_irq;
+ struct at91_adc_state *st = iio_priv(indio);
/* check if we are enabling triggered buffer or the touchscreen */
- if (bitmap_subset(indio_dev->active_scan_mask,
+ if (bitmap_subset(indio->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen enabling */
return at91_adc_configure_touch(st, true);
}
/* if we are not in triggered mode, we cannot enable the buffer. */
- if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
+ if (!(indio->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL;
/* we continue with the triggered buffer */
- ret = at91_adc_dma_start(indio_dev);
+ ret = at91_adc_dma_start(indio);
if (ret) {
- dev_err(&indio_dev->dev, "buffer postenable failed\n");
+ dev_err(&indio->dev, "buffer postenable failed\n");
+ iio_triggered_buffer_predisable(indio);
return ret;
}
- return iio_triggered_buffer_postenable(indio_dev);
+ AT91_ADC_BUFFER_CHECK_USE_IRQ(use_irq);
+
+ for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+ struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
+
+ if (!chan)
+ continue;
+ /* these channel types cannot be handled by this trigger */
+ if (chan->type == IIO_POSITIONRELATIVE ||
+ chan->type == IIO_PRESSURE)
+ continue;
+
+ at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
+ if (use_irq) {
+ at91_adc_writel(st, AT91_SAMA5D2_IER,
+ BIT(chan->channel));
+ }
+ }
+ return iio_triggered_buffer_postenable(indio);
}
-static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
+static int at91_adc_buffer_predisable(struct iio_dev *indio)
{
- struct at91_adc_state *st = iio_priv(indio_dev);
+ struct at91_adc_state *st = iio_priv(indio);
int ret;
u8 bit;
+ bool use_irq;
/* check if we are disabling triggered buffer or the touchscreen */
- if (bitmap_subset(indio_dev->active_scan_mask,
+ if (bitmap_subset(indio->active_scan_mask,
&st->touch_st.channels_bitmask,
AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
/* touchscreen disable */
return at91_adc_configure_touch(st, false);
}
/* if we are not in triggered mode, nothing to do here */
- if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
+ if (!(indio->currentmode & INDIO_ALL_TRIGGERED_MODES))
return -EINVAL;
- /* continue with the triggered buffer */
- ret = iio_triggered_buffer_predisable(indio_dev);
- if (ret < 0)
- dev_err(&indio_dev->dev, "buffer predisable failed\n");
-
- if (!st->dma_st.dma_chan)
- return ret;
-
- /* if we are using DMA we must clear registers and end DMA */
- dmaengine_terminate_sync(st->dma_st.dma_chan);
-
+ AT91_ADC_BUFFER_CHECK_USE_IRQ(use_irq);
/*
- * For each enabled channel we must read the last converted value
+ * For each enable channel we must disable it in hardware.
+ * In the case of DMA, we must read the last converted value
* to clear EOC status and not get a possible interrupt later.
- * This value is being read by DMA from LCDR anyway
+ * This value is being read by DMA from LCDR anyway, so it's not lost.
*/
- for_each_set_bit(bit, indio_dev->active_scan_mask,
- indio_dev->num_channels) {
- struct iio_chan_spec const *chan =
- at91_adc_chan_get(indio_dev, bit);
+ for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+ struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
if (!chan)
continue;
@@ -943,12 +935,29 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
if (chan->type == IIO_POSITIONRELATIVE ||
chan->type == IIO_PRESSURE)
continue;
+
+ if (use_irq) {
+ at91_adc_writel(st, AT91_SAMA5D2_IDR,
+ BIT(chan->channel));
+ }
+ at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
+
if (st->dma_st.dma_chan)
at91_adc_readl(st, chan->address);
}
/* read overflow register to clear possible overflow status */
at91_adc_readl(st, AT91_SAMA5D2_OVER);
+
+ /* continue with the triggered buffer */
+ ret = iio_triggered_buffer_predisable(indio);
+ if (ret < 0)
+ dev_err(&indio->dev, "buffer predisable failed\n");
+
+ /* if we are using DMA we must clear registers and end DMA */
+ if (st->dma_st.dma_chan)
+ dmaengine_terminate_sync(st->dma_st.dma_chan);
+
return ret;
}
@@ -993,8 +1002,8 @@ static int at91_adc_trigger_init(struct iio_dev *indio)
return 0;
}
-static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
- struct iio_poll_func *pf)
+static void at91_adc_read_and_push_channels(struct iio_dev *indio_dev,
+ s64 timestamp)
{
struct at91_adc_state *st = iio_priv(indio_dev);
int i = 0;
@@ -1028,11 +1037,30 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
}
i++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, st->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, st->buffer, timestamp);
+}
+
+static int at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
+ struct iio_poll_func *pf)
+{
+ struct at91_adc_state *st = iio_priv(indio_dev);
+
+ /*
+ * Check if the conversion is ready. If not, schedule a work to
+ * check again later.
+ */
+ if (!(at91_adc_readl(st, AT91_SAMA5D2_ISR) & GENMASK(11, 0))) {
+ schedule_work(&st->workq);
+ return -EINPROGRESS;
+ }
+
+ /* we have data, so let's extract and push it */
+ at91_adc_read_and_push_channels(indio_dev, pf->timestamp);
+
+ return 0;
}
-static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
+static int at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
int transferred_len = at91_adc_dma_size_done(st);
@@ -1079,6 +1107,8 @@ static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
}
/* adjust saved time for next transfer handling */
st->dma_st.dma_ts = iio_get_time_ns(indio_dev);
+
+ return 0;
}
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -1086,33 +1116,41 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(indio_dev);
+ int ret;
+ st->timestamp = pf->timestamp;
if (st->dma_st.dma_chan)
- at91_adc_trigger_handler_dma(indio_dev);
+ ret = at91_adc_trigger_handler_dma(indio_dev);
else
- at91_adc_trigger_handler_nodma(indio_dev, pf);
+ ret = at91_adc_trigger_handler_nodma(indio_dev, pf);
- iio_trigger_notify_done(indio_dev->trig);
+ if (!ret)
+ iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
-static int at91_adc_buffer_init(struct iio_dev *indio)
+irqreturn_t at91_adc_pollfunc(int irq, void *p)
{
- struct at91_adc_state *st = iio_priv(indio);
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct at91_adc_state *st = iio_priv(indio_dev);
- if (st->selected_trig->hw_trig) {
- return devm_iio_triggered_buffer_setup(&indio->dev, indio,
- &iio_pollfunc_store_time,
- &at91_adc_trigger_handler, &at91_buffer_setup_ops);
- }
/*
- * we need to prepare the buffer ops in case we will get
- * another buffer attached (like a callback buffer for the touchscreen)
+ * If it's not our trigger, start a conversion now, as we are
+ * actually polling the trigger now.
*/
- indio->setup_ops = &at91_buffer_setup_ops;
+ if (iio_trigger_validate_own_device(indio_dev->trig, indio_dev))
+ at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
- return 0;
+ return iio_pollfunc_store_time(irq, p);
+}
+
+static int at91_adc_buffer_init(struct iio_dev *indio)
+{
+ return devm_iio_triggered_buffer_setup(&indio->dev, indio,
+ &at91_adc_pollfunc,
+ &at91_adc_trigger_handler, &at91_buffer_setup_ops);
}
static unsigned at91_adc_startup_time(unsigned startup_time_min,
@@ -1195,7 +1233,7 @@ static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
* from our IRQ context. Which is something we better avoid.
* Let's schedule it after our IRQ is completed.
*/
- schedule_work(&st->touch_st.workq);
+ schedule_work(&st->workq);
}
static void at91_adc_pen_detect_interrupt(struct at91_adc_state *st)
@@ -1228,13 +1266,17 @@ static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st)
static void at91_adc_workq_handler(struct work_struct *workq)
{
- struct at91_adc_touch *touch_st = container_of(workq,
- struct at91_adc_touch, workq);
- struct at91_adc_state *st = container_of(touch_st,
- struct at91_adc_state, touch_st);
+ struct at91_adc_state *st = container_of(workq,
+ struct at91_adc_state, workq);
struct iio_dev *indio_dev = iio_priv_to_dev(st);
- iio_push_to_buffers(indio_dev, st->buffer);
+ if ((indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES) &&
+ iio_trigger_validate_own_device(indio_dev->trig, indio_dev)) {
+ at91_adc_read_and_push_channels(indio_dev, st->timestamp);
+ iio_trigger_notify_done(indio_dev->trig);
+ } else {
+ iio_push_to_buffers(indio_dev, st->buffer);
+ }
}
static irqreturn_t at91_adc_interrupt(int irq, void *private)
@@ -1711,7 +1753,7 @@ static int at91_adc_probe(struct platform_device *pdev)
init_waitqueue_head(&st->wq_data_available);
mutex_init(&st->lock);
- INIT_WORK(&st->touch_st.workq, at91_adc_workq_handler);
+ INIT_WORK(&st->workq, at91_adc_workq_handler);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)