diff options
Diffstat (limited to 'drivers/iio/adc/xilinx-xadc-core.c')
-rw-r--r-- | drivers/iio/adc/xilinx-xadc-core.c | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index d4f21d1be6c8..3f6be5ac049a 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -322,6 +322,7 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) #define XADC_ZYNQ_TCK_RATE_MAX 50000000 #define XADC_ZYNQ_IGAP_DEFAULT 20 +#define XADC_ZYNQ_PCAP_RATE_MAX 200000000 static int xadc_zynq_setup(struct platform_device *pdev, struct iio_dev *indio_dev, int irq) @@ -332,6 +333,7 @@ static int xadc_zynq_setup(struct platform_device *pdev, unsigned int div; unsigned int igap; unsigned int tck_rate; + int ret; /* TODO: Figure out how to make igap and tck_rate configurable */ igap = XADC_ZYNQ_IGAP_DEFAULT; @@ -340,9 +342,16 @@ static int xadc_zynq_setup(struct platform_device *pdev, xadc->zynq_intmask = ~0; pcap_rate = clk_get_rate(xadc->clk); + if (!pcap_rate) + return -EINVAL; + + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, + (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); + if (ret) + return ret; + } - if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) - tck_rate = XADC_ZYNQ_TCK_RATE_MAX; if (tck_rate > pcap_rate / 2) { div = 2; } else { @@ -368,6 +377,12 @@ static int xadc_zynq_setup(struct platform_device *pdev, XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, pcap_rate); + if (ret) + return ret; + } + return 0; } @@ -889,6 +904,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev, unsigned long clk_rate = xadc_get_dclk_rate(xadc); unsigned int div; + if (!clk_rate) + return -EINVAL; + if (info != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; @@ -1045,7 +1063,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, unsigned int num_channels; const char *external_mux; u32 ext_mux_chan; - int reg; + u32 reg; int ret; *conf = 0; @@ -1157,6 +1175,7 @@ static int xadc_probe(struct platform_device *pdev) xadc = iio_priv(indio_dev); xadc->ops = id->data; + xadc->irq = irq; init_completion(&xadc->completion); mutex_init(&xadc->mutex); spin_lock_init(&xadc->lock); @@ -1207,14 +1226,14 @@ static int xadc_probe(struct platform_device *pdev) if (ret) goto err_free_samplerate_trigger; - ret = xadc->ops->setup(pdev, indio_dev, irq); + ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0, + dev_name(&pdev->dev), indio_dev); if (ret) goto err_clk_disable_unprepare; - ret = request_irq(irq, xadc->ops->interrupt_handler, 0, - dev_name(&pdev->dev), indio_dev); + ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); if (ret) - goto err_clk_disable_unprepare; + goto err_free_irq; for (i = 0; i < 16; i++) xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), @@ -1239,8 +1258,10 @@ static int xadc_probe(struct platform_device *pdev) goto err_free_irq; /* Disable all alarms */ - xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, - XADC_CONF1_ALARM_MASK); + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, + XADC_CONF1_ALARM_MASK); + if (ret) + goto err_free_irq; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { @@ -1268,7 +1289,7 @@ static int xadc_probe(struct platform_device *pdev) return 0; err_free_irq: - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); err_clk_disable_unprepare: clk_disable_unprepare(xadc->clk); err_free_samplerate_trigger: @@ -1290,7 +1311,6 @@ static int xadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct xadc *xadc = iio_priv(indio_dev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(indio_dev); if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { @@ -1298,7 +1318,7 @@ static int xadc_remove(struct platform_device *pdev) iio_trigger_free(xadc->convst_trigger); iio_triggered_buffer_cleanup(indio_dev); } - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); clk_disable_unprepare(xadc->clk); cancel_delayed_work(&xadc->zynq_unmask_work); kfree(xadc->data); |