OSDN Git Service

iio: xilinx-xadc: Make IRQ optional
authorLars-Peter Clausen <lars@metafoo.de>
Thu, 21 Oct 2021 12:59:50 +0000 (14:59 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Wed, 17 Nov 2021 17:51:32 +0000 (17:51 +0000)
In some setups the IRQ signal of the XADC might not be wired to the host
system. The driver currently requires that an interrupt is specified. Make
the interrupt optional so the driver can be used in such setups where the
interrupt is not connected.

Since both the internal triggers as well as events depend on the interrupt
being connected both are not available when the interrupt is not connected.

Buffered access is still supported even without an interrupt since an
external trigger can be used.

The IRQ is only optional when using the AXI interface, since the PCAP
interface needs the IRQ for reading and writing registers.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Link: https://lore.kernel.org/r/20211021125950.28707-1-lars@metafoo.de
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/xilinx-xadc-core.c

index 83bea5e..2aa4278 100644 (file)
@@ -107,6 +107,7 @@ static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
 #define XADC_AXI_INT_ALARM_MASK                0x3c0f
 
 #define XADC_FLAGS_BUFFERED BIT(0)
+#define XADC_FLAGS_IRQ_OPTIONAL BIT(1)
 
 /*
  * The XADC hardware supports a samplerate of up to 1MSPS. Unfortunately it does
@@ -562,7 +563,7 @@ static const struct xadc_ops xadc_7s_axi_ops = {
        .get_dclk_rate = xadc_axi_get_dclk,
        .update_alarm = xadc_axi_update_alarm,
        .interrupt_handler = xadc_axi_interrupt_handler,
-       .flags = XADC_FLAGS_BUFFERED,
+       .flags = XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL,
        .type = XADC_TYPE_S7,
 };
 
@@ -573,7 +574,7 @@ static const struct xadc_ops xadc_us_axi_ops = {
        .get_dclk_rate = xadc_axi_get_dclk,
        .update_alarm = xadc_axi_update_alarm,
        .interrupt_handler = xadc_axi_interrupt_handler,
-       .flags = XADC_FLAGS_BUFFERED,
+       .flags = XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL,
        .type = XADC_TYPE_US,
 };
 
@@ -1182,7 +1183,7 @@ static const struct of_device_id xadc_of_match_table[] = {
 MODULE_DEVICE_TABLE(of, xadc_of_match_table);
 
 static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
-       unsigned int *conf)
+       unsigned int *conf, int irq)
 {
        struct device *dev = indio_dev->dev.parent;
        struct xadc *xadc = iio_priv(indio_dev);
@@ -1195,6 +1196,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
        u32 ext_mux_chan;
        u32 reg;
        int ret;
+       int i;
 
        *conf = 0;
 
@@ -1273,6 +1275,14 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
        }
        of_node_put(chan_node);
 
+       /* No IRQ => no events */
+       if (irq <= 0) {
+               for (i = 0; i < num_channels; i++) {
+                       channels[i].event_spec = NULL;
+                       channels[i].num_event_specs = 0;
+               }
+       }
+
        indio_dev->num_channels = num_channels;
        indio_dev->channels = devm_krealloc(dev, channels,
                                            sizeof(*channels) * num_channels,
@@ -1307,6 +1317,7 @@ static int xadc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct of_device_id *id;
+       const struct xadc_ops *ops;
        struct iio_dev *indio_dev;
        unsigned int bipolar_mask;
        unsigned int conf0;
@@ -1322,9 +1333,12 @@ static int xadc_probe(struct platform_device *pdev)
        if (!id)
                return -EINVAL;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq <= 0)
-               return -ENXIO;
+       ops = id->data;
+
+       irq = platform_get_irq_optional(pdev, 0);
+       if (irq < 0 &&
+           (irq != -ENXIO || !(ops->flags & XADC_FLAGS_IRQ_OPTIONAL)))
+               return irq;
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*xadc));
        if (!indio_dev)
@@ -1345,7 +1359,7 @@ static int xadc_probe(struct platform_device *pdev)
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &xadc_info;
 
-       ret = xadc_parse_dt(indio_dev, dev->of_node, &conf0);
+       ret = xadc_parse_dt(indio_dev, dev->of_node, &conf0, irq);
        if (ret)
                return ret;
 
@@ -1357,14 +1371,16 @@ static int xadc_probe(struct platform_device *pdev)
                if (ret)
                        return ret;
 
-               xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
-               if (IS_ERR(xadc->convst_trigger))
-                       return PTR_ERR(xadc->convst_trigger);
+               if (irq > 0) {
+                       xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
+                       if (IS_ERR(xadc->convst_trigger))
+                               return PTR_ERR(xadc->convst_trigger);
 
-               xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev,
-                       "samplerate");
-               if (IS_ERR(xadc->samplerate_trigger))
-                       return PTR_ERR(xadc->samplerate_trigger);
+                       xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev,
+                               "samplerate");
+                       if (IS_ERR(xadc->samplerate_trigger))
+                               return PTR_ERR(xadc->samplerate_trigger);
+               }
        }
 
        xadc->clk = devm_clk_get(dev, NULL);
@@ -1396,15 +1412,17 @@ static int xadc_probe(struct platform_device *pdev)
                }
        }
 
-       ret = devm_request_irq(dev, irq, xadc->ops->interrupt_handler, 0,
-                              dev_name(dev), indio_dev);
-       if (ret)
-               return ret;
+       if (irq > 0) {
+               ret = devm_request_irq(dev, irq, xadc->ops->interrupt_handler,
+                                      0, dev_name(dev), indio_dev);
+               if (ret)
+                       return ret;
 
-       ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work,
-                                      &xadc->zynq_unmask_work);
-       if (ret)
-               return ret;
+               ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work,
+                                              &xadc->zynq_unmask_work);
+               if (ret)
+                       return ret;
+       }
 
        ret = xadc->ops->setup(pdev, indio_dev, irq);
        if (ret)