| .. | .. |
|---|
| 1 | | -// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * AD5758 Digital to analog converters driver |
|---|
| 4 | 4 | * |
|---|
| .. | .. |
|---|
| 11 | 11 | #include <linux/kernel.h> |
|---|
| 12 | 12 | #include <linux/module.h> |
|---|
| 13 | 13 | #include <linux/property.h> |
|---|
| 14 | +#include <linux/of.h> |
|---|
| 15 | +#include <linux/of_device.h> |
|---|
| 14 | 16 | #include <linux/spi/spi.h> |
|---|
| 17 | +#include <linux/gpio/consumer.h> |
|---|
| 15 | 18 | |
|---|
| 16 | 19 | #include <linux/iio/iio.h> |
|---|
| 17 | 20 | #include <linux/iio/sysfs.h> |
|---|
| .. | .. |
|---|
| 71 | 74 | #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) |
|---|
| 72 | 75 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) |
|---|
| 73 | 76 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) |
|---|
| 74 | | -#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7) |
|---|
| 75 | | -#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7) |
|---|
| 76 | 77 | |
|---|
| 77 | 78 | /* AD5758_DCDC_CONFIG2 */ |
|---|
| 78 | 79 | #define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) |
|---|
| .. | .. |
|---|
| 83 | 84 | /* AD5758_DIGITAL_DIAG_RESULTS */ |
|---|
| 84 | 85 | #define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) |
|---|
| 85 | 86 | |
|---|
| 87 | +/* AD5758_ADC_CONFIG */ |
|---|
| 88 | +#define AD5758_ADC_CONFIG_PPC_BUF_EN(x) (((x) & 0x1) << 11) |
|---|
| 89 | +#define AD5758_ADC_CONFIG_PPC_BUF_MSK BIT(11) |
|---|
| 90 | + |
|---|
| 86 | 91 | #define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) |
|---|
| 87 | 92 | |
|---|
| 88 | 93 | #define AD5758_FULL_SCALE_MICRO 65535000000ULL |
|---|
| 89 | | - |
|---|
| 90 | | -/** |
|---|
| 91 | | - * struct ad5758_state - driver instance specific data |
|---|
| 92 | | - * @spi: spi_device |
|---|
| 93 | | - * @lock: mutex lock |
|---|
| 94 | | - * @out_range: struct which stores the output range |
|---|
| 95 | | - * @dc_dc_mode: variable which stores the mode of operation |
|---|
| 96 | | - * @dc_dc_ilim: variable which stores the dc-to-dc converter current limit |
|---|
| 97 | | - * @slew_time: variable which stores the target slew time |
|---|
| 98 | | - * @pwr_down: variable which contains whether a channel is powered down or not |
|---|
| 99 | | - * @data: spi transfer buffers |
|---|
| 100 | | - */ |
|---|
| 101 | 94 | |
|---|
| 102 | 95 | struct ad5758_range { |
|---|
| 103 | 96 | int reg; |
|---|
| .. | .. |
|---|
| 105 | 98 | int max; |
|---|
| 106 | 99 | }; |
|---|
| 107 | 100 | |
|---|
| 101 | +/** |
|---|
| 102 | + * struct ad5758_state - driver instance specific data |
|---|
| 103 | + * @spi: spi_device |
|---|
| 104 | + * @lock: mutex lock |
|---|
| 105 | + * @gpio_reset: gpio descriptor for the reset line |
|---|
| 106 | + * @out_range: struct which stores the output range |
|---|
| 107 | + * @dc_dc_mode: variable which stores the mode of operation |
|---|
| 108 | + * @dc_dc_ilim: variable which stores the dc-to-dc converter current limit |
|---|
| 109 | + * @slew_time: variable which stores the target slew time |
|---|
| 110 | + * @pwr_down: variable which contains whether a channel is powered down or not |
|---|
| 111 | + * @d32: spi transfer buffers |
|---|
| 112 | + */ |
|---|
| 108 | 113 | struct ad5758_state { |
|---|
| 109 | 114 | struct spi_device *spi; |
|---|
| 110 | 115 | struct mutex lock; |
|---|
| 116 | + struct gpio_desc *gpio_reset; |
|---|
| 111 | 117 | struct ad5758_range out_range; |
|---|
| 112 | 118 | unsigned int dc_dc_mode; |
|---|
| 113 | 119 | unsigned int dc_dc_ilim; |
|---|
| .. | .. |
|---|
| 116 | 122 | __be32 d32[3]; |
|---|
| 117 | 123 | }; |
|---|
| 118 | 124 | |
|---|
| 119 | | -/** |
|---|
| 125 | +/* |
|---|
| 120 | 126 | * Output ranges corresponding to bits [3:0] from DAC_CONFIG register |
|---|
| 121 | 127 | * 0000: 0 V to 5 V voltage range |
|---|
| 122 | 128 | * 0001: 0 V to 10 V voltage range |
|---|
| .. | .. |
|---|
| 313 | 319 | { |
|---|
| 314 | 320 | int ret; |
|---|
| 315 | 321 | |
|---|
| 322 | + /* |
|---|
| 323 | + * The ENABLE_PPC_BUFFERS bit must be set prior to enabling PPC current |
|---|
| 324 | + * mode. |
|---|
| 325 | + */ |
|---|
| 326 | + if (mode == AD5758_DCDC_MODE_PPC_CURRENT) { |
|---|
| 327 | + ret = ad5758_spi_write_mask(st, AD5758_ADC_CONFIG, |
|---|
| 328 | + AD5758_ADC_CONFIG_PPC_BUF_MSK, |
|---|
| 329 | + AD5758_ADC_CONFIG_PPC_BUF_EN(1)); |
|---|
| 330 | + if (ret < 0) |
|---|
| 331 | + return ret; |
|---|
| 332 | + } |
|---|
| 333 | + |
|---|
| 316 | 334 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, |
|---|
| 317 | 335 | AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, |
|---|
| 318 | 336 | AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); |
|---|
| .. | .. |
|---|
| 442 | 460 | AD5758_CAL_MEM_UNREFRESHED_MSK); |
|---|
| 443 | 461 | } |
|---|
| 444 | 462 | |
|---|
| 445 | | -static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable) |
|---|
| 446 | | -{ |
|---|
| 447 | | - int ret; |
|---|
| 448 | | - |
|---|
| 449 | | - ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, |
|---|
| 450 | | - AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK, |
|---|
| 451 | | - AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable)); |
|---|
| 452 | | - if (ret < 0) |
|---|
| 453 | | - return ret; |
|---|
| 454 | | - /* |
|---|
| 455 | | - * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. |
|---|
| 456 | | - * This allows the 3-wire interface communication to complete. |
|---|
| 457 | | - */ |
|---|
| 458 | | - return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, |
|---|
| 459 | | - AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); |
|---|
| 460 | | -} |
|---|
| 461 | | - |
|---|
| 462 | 463 | static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) |
|---|
| 463 | 464 | { |
|---|
| 464 | 465 | int ret; |
|---|
| .. | .. |
|---|
| 472 | 473 | /* Wait to allow time for the internal calibrations to complete */ |
|---|
| 473 | 474 | return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, |
|---|
| 474 | 475 | AD5758_CAL_MEM_UNREFRESHED_MSK); |
|---|
| 476 | +} |
|---|
| 477 | + |
|---|
| 478 | +static int ad5758_reset(struct ad5758_state *st) |
|---|
| 479 | +{ |
|---|
| 480 | + if (st->gpio_reset) { |
|---|
| 481 | + gpiod_set_value(st->gpio_reset, 0); |
|---|
| 482 | + usleep_range(100, 1000); |
|---|
| 483 | + gpiod_set_value(st->gpio_reset, 1); |
|---|
| 484 | + usleep_range(100, 1000); |
|---|
| 485 | + |
|---|
| 486 | + return 0; |
|---|
| 487 | + } else { |
|---|
| 488 | + /* Perform a software reset */ |
|---|
| 489 | + return ad5758_soft_reset(st); |
|---|
| 490 | + } |
|---|
| 475 | 491 | } |
|---|
| 476 | 492 | |
|---|
| 477 | 493 | static int ad5758_reg_access(struct iio_dev *indio_dev, |
|---|
| .. | .. |
|---|
| 568 | 584 | { |
|---|
| 569 | 585 | struct ad5758_state *st = iio_priv(indio_dev); |
|---|
| 570 | 586 | bool pwr_down; |
|---|
| 571 | | - unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val; |
|---|
| 572 | | - unsigned long int dcdc_config1_msk, dac_config_msk; |
|---|
| 587 | + unsigned int dac_config_mode, val; |
|---|
| 588 | + unsigned long int dac_config_msk; |
|---|
| 573 | 589 | int ret; |
|---|
| 574 | 590 | |
|---|
| 575 | 591 | ret = kstrtobool(buf, &pwr_down); |
|---|
| .. | .. |
|---|
| 577 | 593 | return ret; |
|---|
| 578 | 594 | |
|---|
| 579 | 595 | mutex_lock(&st->lock); |
|---|
| 580 | | - if (pwr_down) { |
|---|
| 581 | | - dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF; |
|---|
| 596 | + if (pwr_down) |
|---|
| 582 | 597 | val = 0; |
|---|
| 583 | | - } else { |
|---|
| 584 | | - dc_dc_mode = st->dc_dc_mode; |
|---|
| 598 | + else |
|---|
| 585 | 599 | val = 1; |
|---|
| 586 | | - } |
|---|
| 587 | | - |
|---|
| 588 | | - dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) | |
|---|
| 589 | | - AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val); |
|---|
| 590 | | - dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK | |
|---|
| 591 | | - AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK; |
|---|
| 592 | | - |
|---|
| 593 | | - ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, |
|---|
| 594 | | - dcdc_config1_msk, |
|---|
| 595 | | - dcdc_config1_mode); |
|---|
| 596 | | - if (ret < 0) |
|---|
| 597 | | - goto err_unlock; |
|---|
| 598 | 600 | |
|---|
| 599 | 601 | dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | |
|---|
| 600 | 602 | AD5758_DAC_CONFIG_INT_EN_MODE(val); |
|---|
| .. | .. |
|---|
| 768 | 770 | { |
|---|
| 769 | 771 | int regval, ret; |
|---|
| 770 | 772 | |
|---|
| 773 | + st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", |
|---|
| 774 | + GPIOD_OUT_HIGH); |
|---|
| 775 | + if (IS_ERR(st->gpio_reset)) |
|---|
| 776 | + return PTR_ERR(st->gpio_reset); |
|---|
| 777 | + |
|---|
| 771 | 778 | /* Disable CRC checks */ |
|---|
| 772 | 779 | ret = ad5758_crc_disable(st); |
|---|
| 773 | 780 | if (ret < 0) |
|---|
| 774 | 781 | return ret; |
|---|
| 775 | 782 | |
|---|
| 776 | | - /* Perform a software reset */ |
|---|
| 777 | | - ret = ad5758_soft_reset(st); |
|---|
| 783 | + /* Perform a reset */ |
|---|
| 784 | + ret = ad5758_reset(st); |
|---|
| 778 | 785 | if (ret < 0) |
|---|
| 779 | 786 | return ret; |
|---|
| 780 | 787 | |
|---|
| .. | .. |
|---|
| 819 | 826 | return ret; |
|---|
| 820 | 827 | } |
|---|
| 821 | 828 | |
|---|
| 822 | | - /* Enable the VIOUT fault protection switch (FPS is closed) */ |
|---|
| 823 | | - ret = ad5758_fault_prot_switch_en(st, 1); |
|---|
| 824 | | - if (ret < 0) |
|---|
| 825 | | - return ret; |
|---|
| 826 | | - |
|---|
| 827 | 829 | /* Power up the DAC and internal (INT) amplifiers */ |
|---|
| 828 | 830 | ret = ad5758_internal_buffers_en(st, 1); |
|---|
| 829 | 831 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 852 | 854 | |
|---|
| 853 | 855 | mutex_init(&st->lock); |
|---|
| 854 | 856 | |
|---|
| 855 | | - indio_dev->dev.parent = &spi->dev; |
|---|
| 856 | 857 | indio_dev->name = spi_get_device_id(spi)->name; |
|---|
| 857 | 858 | indio_dev->info = &ad5758_info; |
|---|
| 858 | 859 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| .. | .. |
|---|
| 882 | 883 | }; |
|---|
| 883 | 884 | MODULE_DEVICE_TABLE(spi, ad5758_id); |
|---|
| 884 | 885 | |
|---|
| 886 | +static const struct of_device_id ad5758_of_match[] = { |
|---|
| 887 | + { .compatible = "adi,ad5758" }, |
|---|
| 888 | + { }, |
|---|
| 889 | +}; |
|---|
| 890 | +MODULE_DEVICE_TABLE(of, ad5758_of_match); |
|---|
| 891 | + |
|---|
| 885 | 892 | static struct spi_driver ad5758_driver = { |
|---|
| 886 | 893 | .driver = { |
|---|
| 887 | 894 | .name = KBUILD_MODNAME, |
|---|
| 895 | + .of_match_table = ad5758_of_match, |
|---|
| 888 | 896 | }, |
|---|
| 889 | 897 | .probe = ad5758_probe, |
|---|
| 890 | 898 | .id_table = ad5758_id, |
|---|