.. | .. |
---|
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, |
---|