diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml index c81285d84db7a2..fe664378c96623 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml @@ -31,6 +31,17 @@ properties: gain of two configuration. type: boolean + reset-gpios: + maxItems: 1 + + clear-gpios: + maxItems: 1 + + ldac-gpios: + description: + LDAC pin to be used as a hardware trigger to update the DAC channels. + maxItems: 1 + required: - compatible - reg @@ -44,6 +55,7 @@ unevaluatedProperties: false examples: - | + #include spi { #address-cells = <1>; #size-cells = <0>; @@ -53,6 +65,9 @@ examples: reg = <0>; vss-supply = <&dac_vss>; vdd-supply = <&dac_vdd>; + reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>; + clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>; + ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_HIGH>; }; }; ... diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081.dts index 02ba09f572cbe5..8c2d29a1005428 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9081.dts @@ -54,7 +54,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9083_fmc_ebz.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9083_fmc_ebz.dts index 757c82b5c6c7bb..868ca852f01e6a 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_ad9083_fmc_ebz.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_ad9083_fmc_ebz.dts @@ -60,7 +60,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts index d548d85416af05..12a33d94e342bc 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002.dts @@ -53,7 +53,6 @@ reg = <0x00060000 0x00000010>; interrupt-parent = <&intc>; interrupts = <0 33 4>; - altr,gpio-bank-width = <19>; altr,interrupt-type = <4>; altr,interrupt_type = <4>; level_trigger = <1>; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002_rx2tx2.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002_rx2tx2.dts index 2b57a8aefeb0ad..cbcad8c515b1cc 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002_rx2tx2.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9002_rx2tx2.dts @@ -53,7 +53,6 @@ reg = <0x00060000 0x00000010>; interrupt-parent = <&intc>; interrupts = <0 33 4>; - altr,gpio-bank-width = <19>; altr,interrupt-type = <4>; altr,interrupt_type = <4>; level_trigger = <1>; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9009.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9009.dts index 9f2a6a45099e84..ad6a9506a38ef0 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9009.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9009.dts @@ -52,7 +52,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9025.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9025.dts index c4fdd87afad70e..50a1ff163d5a9e 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9025.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9025.dts @@ -58,7 +58,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts index 7961e5a8498b94..b3646b2cbd635c 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_adrv9371.dts @@ -51,7 +51,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts index dd52f1676feb15..596061a90d3a2e 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_fmcomms8.dts @@ -53,7 +53,6 @@ sys_gpio_out: gpio@20 { compatible = "altr,pio-1.0"; reg = <0x00000020 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_ad57xx.dts b/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_ad57xx.dts new file mode 100644 index 00000000000000..917a2f2f2af9d3 --- /dev/null +++ b/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_ad57xx.dts @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD5791 + * https://www.analog.com/en/products/ad5791.html + * https://analogdevicesinc.github.io/hdl/projects/ad57xx_ardz/index.html + * https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/EVAL-AD5791ARDZ.html + * https://wiki.analog.com/resources/tools-software/linux-build/generic/socfpga + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2024 Analog Devices Inc. + */ +/dts-v1/; +#include "socfpga_cyclone5_de10_nano_hps.dtsi" +#include +#include +#include + +/ { + dac_vdd: regulator-vdd { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + regulator-always-on; + }; + + dac_vss: regulator-vss { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + regulator-always-on; + }; + +}; + +&fpga_axi { + + adc_trigger: pwm@0x00050000 { + compatible = "adi,axi-pwmgen-2.00.a"; + reg = <0x00050000 0x1000>; + #pwm-cells = <2>; + clocks = <&spi_clk 0>; + }; + + tx_dma: tx-dma@0x00030000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x00030000 0x00000800>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&spi_clk 0>; + }; + + spi_clk: clock-controller@0x00060000 { + compatible = "altr,c5-fpll"; + reg = <0x00060000 0x00000100>; + #clock-cells = <0x1>; + + #address-cells = <1>; + #size-cells = <0>; + clocks = <&sys_clk>; + assigned-clocks = <&spi_clk 0>; + assigned-clock-rates = <185000000>; + clock-output-names = "outclk0"; + adi,fractional-carry-bit = <32>; + + spi_c0: channel@0 { + reg = <0>; + adi,extended-name = "SPI_CLOCK"; + }; + }; + + spi@0x00040000 { + compatible = "adi-ex,axi-spi-engine-1.00.a"; + reg = <0x00040000 0x00010000>; + interrupt-parent = <&intc>; + interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sys_clk>, <&spi_clk 0>; + clock-names = "s_axi_aclk", "spi_clk"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + ad57xx_1: dac@0 { + compatible = "adi,ad5791"; + spi-cpha; + reg = <0>; + spi-max-frequency = <35000000>; + vss-supply = <&dac_vss>; + vdd-supply = <&dac_vdd>; + reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>; + clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>; + ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_LOW>; + + clocks = <&spi_clk 0>; + clock-names = "ref_clk"; + + dmas = <&tx_dma 0>; + dma-names = "tx"; + pwms = <&adc_trigger 0 0>; + pwm-names = "cnv"; + + }; + }; +}; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_hps.dtsi b/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_hps.dtsi index 143fc6fd4502e7..df6bf48a4d85cb 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_hps.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5_de10_nano_hps.dtsi @@ -31,10 +31,17 @@ }; &fpga_axi { + gpio_bd: gpio_bd@0x00010080 { + compatible = "altr,pio-18.1", "altr,pio-1.0"; + reg = <0x00010080 0x00000010>; + resetvalue = <0>; + #gpio-cells = <2>; + gpio-controller; + }; + gpio_in: gpio_in@0x00010100 { compatible = "altr,pio-18.1", "altr,pio-1.0"; reg = <0x00010100 0x00000010>; - altr,gpio-bank-width = <32>; altr,interrupt-type = <4>; altr,interrupt_type = <4>; level_trigger = <1>; @@ -107,7 +114,6 @@ gpio_out: gpio_out@0x00109000 { compatible = "altr,pio-1.0"; reg = <0x00109000 0x00000010>; - altr,gpio-bank-width = <32>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts index 2f89713eae3ed6..5a8a8b4427af36 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit_arradio.dts @@ -172,7 +172,6 @@ gpio: gpio@9000 { compatible = "altr,pio-1.0"; reg = <0x00009000 0x00000010>; - altr,gpio-bank-width = <5>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit_dc2677a.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit_dc2677a.dts index 6b263fa2f8b838..cdc30edb5552ac 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit_dc2677a.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit_dc2677a.dts @@ -145,7 +145,6 @@ gpio: gpio@9000 { compatible = "altr,pio-1.0"; reg = <0x00020000 0x00010000>; - altr,gpio-bank-width = <5>; resetvalue = <0>; #gpio-cells = <2>; gpio-controller; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 75b549827e15a5..9ace6c5fa618b2 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -59,13 +68,22 @@ #define AD5791_DAC_PWRDN_6K 0 #define AD5791_DAC_PWRDN_3STATE 1 +/* + * Arbitrary sane max sampling rate. datasheet only mentions + * max SPI bauderate of 35Mbps (x 24 bits) + */ +#define AD5791_MAX_SAMPLING_RATE 1000000 + /** * struct ad5791_chip_info - chip specific information * @get_lin_comp: function pointer to the device specific function */ struct ad5791_chip_info { - int (*get_lin_comp) (unsigned int span); + const char *name; + const struct iio_chan_spec channel; + const struct iio_chan_spec channel_offload; + const int (*get_lin_comp)(unsigned int span); }; /** @@ -85,7 +103,14 @@ struct ad5791_state { struct spi_device *spi; struct regulator *reg_vdd; struct regulator *reg_vss; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_clear; + struct gpio_desc *gpio_ldac; const struct ad5791_chip_info *chip_info; + struct spi_message spi_msg; + struct spi_transfer spi_transfer; + struct pwm_device *cnv_trigger; + unsigned long ref_clk_rate; unsigned short vref_mv; unsigned int vref_neg_mv; unsigned ctrl; @@ -98,13 +123,6 @@ struct ad5791_state { } data[3] __aligned(IIO_DMA_MINALIGN); }; -enum ad5791_supported_device_ids { - ID_AD5760, - ID_AD5780, - ID_AD5781, - ID_AD5791, -}; - static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val) { st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE | @@ -228,20 +246,46 @@ static int ad5780_get_lin_comp(unsigned int span) else return AD5780_LINCOMP_10_20; } -static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { - [ID_AD5760] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5780] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5781] = { - .get_lin_comp = ad5791_get_lin_comp, - }, - [ID_AD5791] = { - .get_lin_comp = ad5791_get_lin_comp, - }, -}; + +static int ad5791_get_sampling_freq(struct ad5791_state *st) +{ + return DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, + pwm_get_period(st->cnv_trigger)); +} + +static int __ad5791_set_sampling_freq(struct ad5791_state *st, int freq) +{ + struct pwm_state cnv_state; + u32 rem; + + pwm_init_state(st->cnv_trigger, &cnv_state); + cnv_state.period = div_u64_rem((u64)DIV_ROUND_UP(st->ref_clk_rate, freq) * NSEC_PER_SEC, + st->ref_clk_rate, &rem); + if (rem) + cnv_state.period += 1; + + cnv_state.duty_cycle = DIV_ROUND_UP(NSEC_PER_SEC, st->ref_clk_rate); + + return pwm_apply_state(st->cnv_trigger, &cnv_state); +} + +static int ad5791_set_sampling_freq(struct iio_dev *indio_dev, unsigned int freq) +{ + struct ad5791_state *st = iio_priv(indio_dev); + int ret; + + if (!freq || freq > AD5791_MAX_SAMPLING_RATE) + return -EINVAL; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = __ad5791_set_sampling_freq(st, freq); + iio_device_release_direct_mode(indio_dev); + + return ret; +} static int ad5791_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -270,6 +314,9 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, do_div(val64, st->vref_mv); *val = -val64; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = ad5791_get_sampling_freq(st); + return IIO_VAL_INT; default: return -EINVAL; } @@ -289,30 +336,52 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { }, }; -#define AD5791_CHAN(bits, _shift) { \ - .type = IIO_VOLTAGE, \ - .output = 1, \ - .indexed = 1, \ - .address = AD5791_ADDR_DAC0, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (bits), \ - .storagebits = 24, \ - .shift = (_shift), \ - }, \ - .ext_info = ad5791_ext_info, \ +#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \ +static const struct ad5791_chip_info _name##_chip_info = { \ + .name = #_name, \ + .get_lin_comp = &(_lin_comp), \ + .channel = { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 24, \ + .shift = (_shift), \ + }, \ + .ext_info = ad5791_ext_info, \ + }, \ + .channel_offload = { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 32, \ + .shift = (_shift), \ + }, \ + .ext_info = ad5791_ext_info, \ + }, \ } -static const struct iio_chan_spec ad5791_channels[] = { - [ID_AD5760] = AD5791_CHAN(16, 4), - [ID_AD5780] = AD5791_CHAN(18, 2), - [ID_AD5781] = AD5791_CHAN(18, 2), - [ID_AD5791] = AD5791_CHAN(20, 0) -}; +AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5780, 18, 2, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5781, 18, 2, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5790, 20, 0, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5791, 20, 0, ad5791_get_lin_comp); static int ad5791_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -328,12 +397,103 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, val <<= chan->scan_type.shift; return ad5791_spi_write(st, chan->address, val); - + case IIO_CHAN_INFO_SAMP_FREQ: + return ad5791_set_sampling_freq(indio_dev, val); default: return -EINVAL; } } +static int ad5791_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + int ret; + + if (st->pwr_down) + return -EINVAL; + + ret = pwm_enable(st->cnv_trigger); + if (ret) + return ret; + + spi_bus_lock(st->spi->master); + spi_engine_ex_offload_enable(st->spi, true); + + return 0; +} + +static int ad5791_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + + spi_engine_ex_offload_enable(st->spi, false); + spi_bus_unlock(st->spi->master); + pwm_disable(st->cnv_trigger); + + return 0; +} + +static const struct iio_buffer_setup_ops ad5791_buffer_setup_ops = { + .preenable = &ad5791_buffer_preenable, + .postdisable = &ad5791_buffer_postdisable, +}; + +static void ad5791_pwm_diasble(void *data) +{ + pwm_disable(data); +} + +static int ad5791_pwm_setup(struct spi_device *spi, struct ad5791_state *st) +{ + struct clk *ref_clk; + int ret; + + ref_clk = devm_clk_get_enabled(&spi->dev, "ref_clk"); + if (IS_ERR(ref_clk)) + return PTR_ERR(ref_clk); + + st->ref_clk_rate = clk_get_rate(ref_clk); + + st->cnv_trigger = devm_pwm_get(&spi->dev, "cnv"); + if (IS_ERR(st->cnv_trigger)) + return PTR_ERR(st->cnv_trigger); + + ret = devm_add_action_or_reset(&spi->dev, ad5791_pwm_diasble, + st->cnv_trigger); + if (ret) + return ret; + + return __ad5791_set_sampling_freq(st, AD5791_MAX_SAMPLING_RATE); +} + +static int ad5791_offload_setup(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + int ret; + + st->spi_transfer.len = 4; + st->spi_transfer.bits_per_word = 24; + st->spi_transfer.tx_buf = (void *)-1; /* steaming tx */ + + spi_message_init_with_transfers(&st->spi_msg, &st->spi_transfer, 1); + + ret = devm_spi_optimize_message(&st->spi->dev, st->spi, &st->spi_msg); + if (ret) + return ret; + + ret = spi_engine_ex_offload_load_msg(st->spi, &st->spi_msg); + if (ret < 0) + return ret; + + ret = ad5791_pwm_setup(st->spi, st); + if (ret) + return ret; + + return devm_iio_dmaengine_buffer_setup(&st->spi->dev, + indio_dev, "tx", + IIO_BUFFER_DIRECTION_OUT); +} + static const struct iio_info ad5791_info = { .read_raw = &ad5791_read_raw, .write_raw = &ad5791_write_raw, @@ -351,32 +511,6 @@ static int ad5791_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg_vdd = devm_regulator_get(&spi->dev, "vdd"); - if (!IS_ERR(st->reg_vdd)) { - ret = regulator_enable(st->reg_vdd); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg_vdd); - if (ret < 0) - goto error_disable_reg_pos; - - pos_voltage_uv = ret; - } - - st->reg_vss = devm_regulator_get(&spi->dev, "vss"); - if (!IS_ERR(st->reg_vss)) { - ret = regulator_enable(st->reg_vss); - if (ret) - goto error_disable_reg_pos; - - ret = regulator_get_voltage(st->reg_vss); - if (ret < 0) - goto error_disable_reg_neg; - - neg_voltage_uv = ret; - } - st->pwr_down = true; st->spi = spi; @@ -386,7 +520,15 @@ static int ad5791_probe(struct spi_device *spi) use_rbuf_gain2 = device_property_read_bool(&spi->dev, "adi,rbuf-gain2-en"); - if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) { + pos_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vdd"); + if (pos_voltage_uv < 0 && pos_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, ret, "failed to get vdd voltage\n"); + + neg_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vss"); + if (neg_voltage_uv < 0 && neg_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, ret, "failed to get vss voltage\n"); + + if (neg_voltage_uv >= 0 && pos_voltage_uv >= 0) { st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000; st->vref_neg_mv = neg_voltage_uv / 1000; } else if (pdata) { @@ -396,13 +538,33 @@ static int ad5791_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage unspecified\n"); } - ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); - if (ret) - goto error_disable_reg_neg; + st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; + st->gpio_clear = devm_gpiod_get_optional(&spi->dev, "clear", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_clear)) + return PTR_ERR(st->gpio_clear); + st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_ldac)) + return PTR_ERR(st->gpio_ldac); + + if (st->gpio_reset) { + fsleep(20); + gpiod_set_value_cansleep(st->gpio_reset, 0); + } else { + ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); + if (ret) + return dev_err_probe(&spi->dev, ret, "fail to reset\n"); + } + + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return dev_err_probe(&spi->dev, -EINVAL, "no chip info\n"); st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) | @@ -411,59 +573,51 @@ static int ad5791_probe(struct spi_device *spi) ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); if (ret) - goto error_disable_reg_neg; + return dev_err_probe(&spi->dev, ret, "fail to write ctrl register\n"); - spi_set_drvdata(spi, indio_dev); indio_dev->info = &ad5791_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels - = &ad5791_channels[spi_get_device_id(spi)->driver_data]; + indio_dev->channels = &st->chip_info->channel; indio_dev->num_channels = 1; - indio_dev->name = spi_get_device_id(st->spi)->name; - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg_neg; - - return 0; + indio_dev->name = st->chip_info->name; + if (spi_engine_ex_offload_supported(spi)) { + indio_dev->channels = &st->chip_info->channel_offload; + indio_dev->setup_ops = &ad5791_buffer_setup_ops; + ret = ad5791_offload_setup(indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "fail to setup offload\n"); + } -error_disable_reg_neg: - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -error_disable_reg_pos: - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - return ret; + return devm_iio_device_register(&spi->dev, indio_dev); } -static void ad5791_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5791_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -} +static const struct of_device_id ad5791_of_match[] = { + { .compatible = "adi,ad5760", .data = &ad5760_chip_info }, + { .compatible = "adi,ad5780", .data = &ad5780_chip_info }, + { .compatible = "adi,ad5781", .data = &ad5781_chip_info }, + { .compatible = "adi,ad5790", .data = &ad5790_chip_info }, + { .compatible = "adi,ad5791", .data = &ad5791_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5791_of_match); static const struct spi_device_id ad5791_id[] = { - {"ad5760", ID_AD5760}, - {"ad5780", ID_AD5780}, - {"ad5781", ID_AD5781}, - {"ad5790", ID_AD5791}, - {"ad5791", ID_AD5791}, - {} + { "ad5760", (kernel_ulong_t)&ad5760_chip_info }, + { "ad5780", (kernel_ulong_t)&ad5780_chip_info }, + { "ad5781", (kernel_ulong_t)&ad5781_chip_info }, + { "ad5790", (kernel_ulong_t)&ad5790_chip_info }, + { "ad5791", (kernel_ulong_t)&ad5791_chip_info }, + { } }; MODULE_DEVICE_TABLE(spi, ad5791_id); static struct spi_driver ad5791_driver = { .driver = { .name = "ad5791", + .of_match_table = ad5791_of_match, }, .probe = ad5791_probe, - .remove = ad5791_remove, .id_table = ad5791_id, }; module_spi_driver(ad5791_driver); diff --git a/drivers/spi/spi-axi-spi-engine-ex.c b/drivers/spi/spi-axi-spi-engine-ex.c index 3d1de2b9829b9e..43eb3835237d0c 100644 --- a/drivers/spi/spi-axi-spi-engine-ex.c +++ b/drivers/spi/spi-axi-spi-engine-ex.c @@ -369,7 +369,7 @@ int spi_engine_ex_offload_load_msg(struct spi_device *spi, /* TODO: validate that we don't exceed the offload SDO FIFO size */ list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!xfer->tx_buf) + if (!xfer->tx_buf || xfer->tx_buf == (void *)-1) continue; if (xfer->bits_per_word <= 8) {