128d1a7acSStefan Popa // SPDX-License-Identifier: GPL-2.0+ 228d1a7acSStefan Popa /* 328d1a7acSStefan Popa * AD5758 Digital to analog converters driver 428d1a7acSStefan Popa * 528d1a7acSStefan Popa * Copyright 2018 Analog Devices Inc. 628d1a7acSStefan Popa * 728d1a7acSStefan Popa * TODO: Currently CRC is not supported in this driver 828d1a7acSStefan Popa */ 928d1a7acSStefan Popa #include <linux/bsearch.h> 1028d1a7acSStefan Popa #include <linux/delay.h> 1128d1a7acSStefan Popa #include <linux/kernel.h> 1228d1a7acSStefan Popa #include <linux/module.h> 1328d1a7acSStefan Popa #include <linux/property.h> 1428d1a7acSStefan Popa #include <linux/spi/spi.h> 1528d1a7acSStefan Popa 1628d1a7acSStefan Popa #include <linux/iio/iio.h> 1728d1a7acSStefan Popa #include <linux/iio/sysfs.h> 1828d1a7acSStefan Popa 1928d1a7acSStefan Popa /* AD5758 registers definition */ 2028d1a7acSStefan Popa #define AD5758_NOP 0x00 2128d1a7acSStefan Popa #define AD5758_DAC_INPUT 0x01 2228d1a7acSStefan Popa #define AD5758_DAC_OUTPUT 0x02 2328d1a7acSStefan Popa #define AD5758_CLEAR_CODE 0x03 2428d1a7acSStefan Popa #define AD5758_USER_GAIN 0x04 2528d1a7acSStefan Popa #define AD5758_USER_OFFSET 0x05 2628d1a7acSStefan Popa #define AD5758_DAC_CONFIG 0x06 2728d1a7acSStefan Popa #define AD5758_SW_LDAC 0x07 2828d1a7acSStefan Popa #define AD5758_KEY 0x08 2928d1a7acSStefan Popa #define AD5758_GP_CONFIG1 0x09 3028d1a7acSStefan Popa #define AD5758_GP_CONFIG2 0x0A 3128d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1 0x0B 3228d1a7acSStefan Popa #define AD5758_DCDC_CONFIG2 0x0C 3328d1a7acSStefan Popa #define AD5758_WDT_CONFIG 0x0F 3428d1a7acSStefan Popa #define AD5758_DIGITAL_DIAG_CONFIG 0x10 3528d1a7acSStefan Popa #define AD5758_ADC_CONFIG 0x11 3628d1a7acSStefan Popa #define AD5758_FAULT_PIN_CONFIG 0x12 3728d1a7acSStefan Popa #define AD5758_TWO_STAGE_READBACK_SELECT 0x13 3828d1a7acSStefan Popa #define AD5758_DIGITAL_DIAG_RESULTS 0x14 3928d1a7acSStefan Popa #define AD5758_ANALOG_DIAG_RESULTS 0x15 4028d1a7acSStefan Popa #define AD5758_STATUS 0x16 4128d1a7acSStefan Popa #define AD5758_CHIP_ID 0x17 4228d1a7acSStefan Popa #define AD5758_FREQ_MONITOR 0x18 4328d1a7acSStefan Popa #define AD5758_DEVICE_ID_0 0x19 4428d1a7acSStefan Popa #define AD5758_DEVICE_ID_1 0x1A 4528d1a7acSStefan Popa #define AD5758_DEVICE_ID_2 0x1B 4628d1a7acSStefan Popa #define AD5758_DEVICE_ID_3 0x1C 4728d1a7acSStefan Popa 4828d1a7acSStefan Popa /* AD5758_DAC_CONFIG */ 4928d1a7acSStefan Popa #define AD5758_DAC_CONFIG_RANGE_MSK GENMASK(3, 0) 5028d1a7acSStefan Popa #define AD5758_DAC_CONFIG_RANGE_MODE(x) (((x) & 0xF) << 0) 5128d1a7acSStefan Popa #define AD5758_DAC_CONFIG_INT_EN_MSK BIT(5) 5228d1a7acSStefan Popa #define AD5758_DAC_CONFIG_INT_EN_MODE(x) (((x) & 0x1) << 5) 5328d1a7acSStefan Popa #define AD5758_DAC_CONFIG_OUT_EN_MSK BIT(6) 5428d1a7acSStefan Popa #define AD5758_DAC_CONFIG_OUT_EN_MODE(x) (((x) & 0x1) << 6) 5528d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_EN_MSK BIT(8) 5628d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_EN_MODE(x) (((x) & 0x1) << 8) 5728d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9) 5828d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_CLOCK_MODE(x) (((x) & 0xF) << 9) 5928d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13) 6028d1a7acSStefan Popa #define AD5758_DAC_CONFIG_SR_STEP_MODE(x) (((x) & 0x7) << 13) 6128d1a7acSStefan Popa 6228d1a7acSStefan Popa /* AD5758_KEY */ 6328d1a7acSStefan Popa #define AD5758_KEY_CODE_RESET_1 0x15FA 6428d1a7acSStefan Popa #define AD5758_KEY_CODE_RESET_2 0xAF51 6528d1a7acSStefan Popa #define AD5758_KEY_CODE_SINGLE_ADC_CONV 0x1ADC 6628d1a7acSStefan Popa #define AD5758_KEY_CODE_RESET_WDT 0x0D06 6728d1a7acSStefan Popa #define AD5758_KEY_CODE_CALIB_MEM_REFRESH 0xFCBA 6828d1a7acSStefan Popa 6928d1a7acSStefan Popa /* AD5758_DCDC_CONFIG1 */ 7028d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MSK GENMASK(4, 0) 7128d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) 7228d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) 7328d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) 7428d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7) 7528d1a7acSStefan Popa #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7) 7628d1a7acSStefan Popa 7728d1a7acSStefan Popa /* AD5758_DCDC_CONFIG2 */ 7828d1a7acSStefan Popa #define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) 7928d1a7acSStefan Popa #define AD5758_DCDC_CONFIG2_ILIMIT_MODE(x) (((x) & 0x7) << 1) 8028d1a7acSStefan Popa #define AD5758_DCDC_CONFIG2_INTR_SAT_3WI_MSK BIT(11) 8128d1a7acSStefan Popa #define AD5758_DCDC_CONFIG2_BUSY_3WI_MSK BIT(12) 8228d1a7acSStefan Popa 8328d1a7acSStefan Popa /* AD5758_DIGITAL_DIAG_RESULTS */ 8428d1a7acSStefan Popa #define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) 8528d1a7acSStefan Popa 8628d1a7acSStefan Popa #define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) 8728d1a7acSStefan Popa 8828d1a7acSStefan Popa #define AD5758_FULL_SCALE_MICRO 65535000000ULL 8928d1a7acSStefan Popa 9028d1a7acSStefan Popa /** 9128d1a7acSStefan Popa * struct ad5758_state - driver instance specific data 9228d1a7acSStefan Popa * @spi: spi_device 9328d1a7acSStefan Popa * @lock: mutex lock 9428d1a7acSStefan Popa * @out_range: struct which stores the output range 9528d1a7acSStefan Popa * @dc_dc_mode: variable which stores the mode of operation 9628d1a7acSStefan Popa * @dc_dc_ilim: variable which stores the dc-to-dc converter current limit 9728d1a7acSStefan Popa * @slew_time: variable which stores the target slew time 9828d1a7acSStefan Popa * @pwr_down: variable which contains whether a channel is powered down or not 9928d1a7acSStefan Popa * @data: spi transfer buffers 10028d1a7acSStefan Popa */ 10128d1a7acSStefan Popa 10228d1a7acSStefan Popa struct ad5758_range { 10328d1a7acSStefan Popa int reg; 10428d1a7acSStefan Popa int min; 10528d1a7acSStefan Popa int max; 10628d1a7acSStefan Popa }; 10728d1a7acSStefan Popa 10828d1a7acSStefan Popa struct ad5758_state { 10928d1a7acSStefan Popa struct spi_device *spi; 11028d1a7acSStefan Popa struct mutex lock; 11128d1a7acSStefan Popa struct ad5758_range out_range; 11228d1a7acSStefan Popa unsigned int dc_dc_mode; 11328d1a7acSStefan Popa unsigned int dc_dc_ilim; 11428d1a7acSStefan Popa unsigned int slew_time; 11528d1a7acSStefan Popa bool pwr_down; 11628d1a7acSStefan Popa __be32 d32[3]; 11728d1a7acSStefan Popa }; 11828d1a7acSStefan Popa 11928d1a7acSStefan Popa /** 12028d1a7acSStefan Popa * Output ranges corresponding to bits [3:0] from DAC_CONFIG register 12128d1a7acSStefan Popa * 0000: 0 V to 5 V voltage range 12228d1a7acSStefan Popa * 0001: 0 V to 10 V voltage range 12328d1a7acSStefan Popa * 0010: ±5 V voltage range 12428d1a7acSStefan Popa * 0011: ±10 V voltage range 12528d1a7acSStefan Popa * 1000: 0 mA to 20 mA current range 12628d1a7acSStefan Popa * 1001: 0 mA to 24 mA current range 12728d1a7acSStefan Popa * 1010: 4 mA to 20 mA current range 12828d1a7acSStefan Popa * 1011: ±20 mA current range 12928d1a7acSStefan Popa * 1100: ±24 mA current range 13028d1a7acSStefan Popa * 1101: -1 mA to +22 mA current range 13128d1a7acSStefan Popa */ 13228d1a7acSStefan Popa enum ad5758_output_range { 13328d1a7acSStefan Popa AD5758_RANGE_0V_5V, 13428d1a7acSStefan Popa AD5758_RANGE_0V_10V, 13528d1a7acSStefan Popa AD5758_RANGE_PLUSMINUS_5V, 13628d1a7acSStefan Popa AD5758_RANGE_PLUSMINUS_10V, 13728d1a7acSStefan Popa AD5758_RANGE_0mA_20mA = 8, 13828d1a7acSStefan Popa AD5758_RANGE_0mA_24mA, 13928d1a7acSStefan Popa AD5758_RANGE_4mA_24mA, 14028d1a7acSStefan Popa AD5758_RANGE_PLUSMINUS_20mA, 14128d1a7acSStefan Popa AD5758_RANGE_PLUSMINUS_24mA, 14228d1a7acSStefan Popa AD5758_RANGE_MINUS_1mA_PLUS_22mA, 14328d1a7acSStefan Popa }; 14428d1a7acSStefan Popa 14528d1a7acSStefan Popa enum ad5758_dc_dc_mode { 14628d1a7acSStefan Popa AD5758_DCDC_MODE_POWER_OFF, 14728d1a7acSStefan Popa AD5758_DCDC_MODE_DPC_CURRENT, 14828d1a7acSStefan Popa AD5758_DCDC_MODE_DPC_VOLTAGE, 14928d1a7acSStefan Popa AD5758_DCDC_MODE_PPC_CURRENT, 15028d1a7acSStefan Popa }; 15128d1a7acSStefan Popa 15228d1a7acSStefan Popa static const struct ad5758_range ad5758_voltage_range[] = { 15328d1a7acSStefan Popa { AD5758_RANGE_0V_5V, 0, 5000000 }, 15428d1a7acSStefan Popa { AD5758_RANGE_0V_10V, 0, 10000000 }, 15528d1a7acSStefan Popa { AD5758_RANGE_PLUSMINUS_5V, -5000000, 5000000 }, 15628d1a7acSStefan Popa { AD5758_RANGE_PLUSMINUS_10V, -10000000, 10000000 } 15728d1a7acSStefan Popa }; 15828d1a7acSStefan Popa 15928d1a7acSStefan Popa static const struct ad5758_range ad5758_current_range[] = { 16028d1a7acSStefan Popa { AD5758_RANGE_0mA_20mA, 0, 20000}, 16128d1a7acSStefan Popa { AD5758_RANGE_0mA_24mA, 0, 24000 }, 16228d1a7acSStefan Popa { AD5758_RANGE_4mA_24mA, 4, 24000 }, 16328d1a7acSStefan Popa { AD5758_RANGE_PLUSMINUS_20mA, -20000, 20000 }, 16428d1a7acSStefan Popa { AD5758_RANGE_PLUSMINUS_24mA, -24000, 24000 }, 16528d1a7acSStefan Popa { AD5758_RANGE_MINUS_1mA_PLUS_22mA, -1000, 22000 }, 16628d1a7acSStefan Popa }; 16728d1a7acSStefan Popa 16828d1a7acSStefan Popa static const int ad5758_sr_clk[16] = { 16928d1a7acSStefan Popa 240000, 200000, 150000, 128000, 64000, 32000, 16000, 8000, 4000, 2000, 17028d1a7acSStefan Popa 1000, 512, 256, 128, 64, 16 17128d1a7acSStefan Popa }; 17228d1a7acSStefan Popa 17328d1a7acSStefan Popa static const int ad5758_sr_step[8] = { 17428d1a7acSStefan Popa 4, 12, 64, 120, 256, 500, 1820, 2048 17528d1a7acSStefan Popa }; 17628d1a7acSStefan Popa 17728d1a7acSStefan Popa static const int ad5758_dc_dc_ilim[6] = { 17828d1a7acSStefan Popa 150000, 200000, 250000, 300000, 350000, 400000 17928d1a7acSStefan Popa }; 18028d1a7acSStefan Popa 18128d1a7acSStefan Popa static int ad5758_spi_reg_read(struct ad5758_state *st, unsigned int addr) 18228d1a7acSStefan Popa { 18328d1a7acSStefan Popa struct spi_transfer t[] = { 18428d1a7acSStefan Popa { 18528d1a7acSStefan Popa .tx_buf = &st->d32[0], 18628d1a7acSStefan Popa .len = 4, 18728d1a7acSStefan Popa .cs_change = 1, 18828d1a7acSStefan Popa }, { 18928d1a7acSStefan Popa .tx_buf = &st->d32[1], 19028d1a7acSStefan Popa .rx_buf = &st->d32[2], 19128d1a7acSStefan Popa .len = 4, 19228d1a7acSStefan Popa }, 19328d1a7acSStefan Popa }; 19428d1a7acSStefan Popa int ret; 19528d1a7acSStefan Popa 19628d1a7acSStefan Popa st->d32[0] = cpu_to_be32( 19728d1a7acSStefan Popa (AD5758_WR_FLAG_MSK(AD5758_TWO_STAGE_READBACK_SELECT) << 24) | 19828d1a7acSStefan Popa (addr << 8)); 19928d1a7acSStefan Popa st->d32[1] = cpu_to_be32(AD5758_WR_FLAG_MSK(AD5758_NOP) << 24); 20028d1a7acSStefan Popa 20128d1a7acSStefan Popa ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); 20228d1a7acSStefan Popa if (ret < 0) 20328d1a7acSStefan Popa return ret; 20428d1a7acSStefan Popa 20528d1a7acSStefan Popa return (be32_to_cpu(st->d32[2]) >> 8) & 0xFFFF; 20628d1a7acSStefan Popa } 20728d1a7acSStefan Popa 20828d1a7acSStefan Popa static int ad5758_spi_reg_write(struct ad5758_state *st, 20928d1a7acSStefan Popa unsigned int addr, 21028d1a7acSStefan Popa unsigned int val) 21128d1a7acSStefan Popa { 21228d1a7acSStefan Popa st->d32[0] = cpu_to_be32((AD5758_WR_FLAG_MSK(addr) << 24) | 21328d1a7acSStefan Popa ((val & 0xFFFF) << 8)); 21428d1a7acSStefan Popa 21528d1a7acSStefan Popa return spi_write(st->spi, &st->d32[0], sizeof(st->d32[0])); 21628d1a7acSStefan Popa } 21728d1a7acSStefan Popa 21828d1a7acSStefan Popa static int ad5758_spi_write_mask(struct ad5758_state *st, 21928d1a7acSStefan Popa unsigned int addr, 22028d1a7acSStefan Popa unsigned long int mask, 22128d1a7acSStefan Popa unsigned int val) 22228d1a7acSStefan Popa { 22328d1a7acSStefan Popa int regval; 22428d1a7acSStefan Popa 22528d1a7acSStefan Popa regval = ad5758_spi_reg_read(st, addr); 22628d1a7acSStefan Popa if (regval < 0) 22728d1a7acSStefan Popa return regval; 22828d1a7acSStefan Popa 22928d1a7acSStefan Popa regval &= ~mask; 23028d1a7acSStefan Popa regval |= val; 23128d1a7acSStefan Popa 23228d1a7acSStefan Popa return ad5758_spi_reg_write(st, addr, regval); 23328d1a7acSStefan Popa } 23428d1a7acSStefan Popa 23528d1a7acSStefan Popa static int cmpfunc(const void *a, const void *b) 23628d1a7acSStefan Popa { 23728d1a7acSStefan Popa return *(int *)a - *(int *)b; 23828d1a7acSStefan Popa } 23928d1a7acSStefan Popa 24028d1a7acSStefan Popa static int ad5758_find_closest_match(const int *array, 24128d1a7acSStefan Popa unsigned int size, int val) 24228d1a7acSStefan Popa { 24328d1a7acSStefan Popa int i; 24428d1a7acSStefan Popa 24528d1a7acSStefan Popa for (i = 0; i < size; i++) { 24628d1a7acSStefan Popa if (val <= array[i]) 24728d1a7acSStefan Popa return i; 24828d1a7acSStefan Popa } 24928d1a7acSStefan Popa 25028d1a7acSStefan Popa return size - 1; 25128d1a7acSStefan Popa } 25228d1a7acSStefan Popa 25328d1a7acSStefan Popa static int ad5758_wait_for_task_complete(struct ad5758_state *st, 25428d1a7acSStefan Popa unsigned int reg, 25528d1a7acSStefan Popa unsigned int mask) 25628d1a7acSStefan Popa { 25728d1a7acSStefan Popa unsigned int timeout; 25828d1a7acSStefan Popa int ret; 25928d1a7acSStefan Popa 26028d1a7acSStefan Popa timeout = 10; 26128d1a7acSStefan Popa do { 26228d1a7acSStefan Popa ret = ad5758_spi_reg_read(st, reg); 26328d1a7acSStefan Popa if (ret < 0) 26428d1a7acSStefan Popa return ret; 26528d1a7acSStefan Popa 26628d1a7acSStefan Popa if (!(ret & mask)) 26728d1a7acSStefan Popa return 0; 26828d1a7acSStefan Popa 26928d1a7acSStefan Popa usleep_range(100, 1000); 27028d1a7acSStefan Popa } while (--timeout); 27128d1a7acSStefan Popa 27228d1a7acSStefan Popa dev_err(&st->spi->dev, 27328d1a7acSStefan Popa "Error reading bit 0x%x in 0x%x register\n", mask, reg); 27428d1a7acSStefan Popa 27528d1a7acSStefan Popa return -EIO; 27628d1a7acSStefan Popa } 27728d1a7acSStefan Popa 27828d1a7acSStefan Popa static int ad5758_calib_mem_refresh(struct ad5758_state *st) 27928d1a7acSStefan Popa { 28028d1a7acSStefan Popa int ret; 28128d1a7acSStefan Popa 28228d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, AD5758_KEY, 28328d1a7acSStefan Popa AD5758_KEY_CODE_CALIB_MEM_REFRESH); 28428d1a7acSStefan Popa if (ret < 0) { 28528d1a7acSStefan Popa dev_err(&st->spi->dev, 28628d1a7acSStefan Popa "Failed to initiate a calibration memory refresh\n"); 28728d1a7acSStefan Popa return ret; 28828d1a7acSStefan Popa } 28928d1a7acSStefan Popa 29028d1a7acSStefan Popa /* Wait to allow time for the internal calibrations to complete */ 29128d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 29228d1a7acSStefan Popa AD5758_CAL_MEM_UNREFRESHED_MSK); 29328d1a7acSStefan Popa } 29428d1a7acSStefan Popa 29528d1a7acSStefan Popa static int ad5758_soft_reset(struct ad5758_state *st) 29628d1a7acSStefan Popa { 29728d1a7acSStefan Popa int ret; 29828d1a7acSStefan Popa 29928d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_1); 30028d1a7acSStefan Popa if (ret < 0) 30128d1a7acSStefan Popa return ret; 30228d1a7acSStefan Popa 30328d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_2); 30428d1a7acSStefan Popa 30528d1a7acSStefan Popa /* Perform a software reset and wait at least 100us */ 30628d1a7acSStefan Popa usleep_range(100, 1000); 30728d1a7acSStefan Popa 30828d1a7acSStefan Popa return ret; 30928d1a7acSStefan Popa } 31028d1a7acSStefan Popa 31128d1a7acSStefan Popa static int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st, 31228d1a7acSStefan Popa enum ad5758_dc_dc_mode mode) 31328d1a7acSStefan Popa { 31428d1a7acSStefan Popa int ret; 31528d1a7acSStefan Popa 31628d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, 31728d1a7acSStefan Popa AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, 31828d1a7acSStefan Popa AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); 31928d1a7acSStefan Popa if (ret < 0) 32028d1a7acSStefan Popa return ret; 32128d1a7acSStefan Popa 32228d1a7acSStefan Popa /* 32328d1a7acSStefan Popa * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. 32428d1a7acSStefan Popa * This allows the 3-wire interface communication to complete. 32528d1a7acSStefan Popa */ 32628d1a7acSStefan Popa ret = ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, 32728d1a7acSStefan Popa AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); 32828d1a7acSStefan Popa if (ret < 0) 32928d1a7acSStefan Popa return ret; 33028d1a7acSStefan Popa 33128d1a7acSStefan Popa st->dc_dc_mode = mode; 33228d1a7acSStefan Popa 33328d1a7acSStefan Popa return ret; 33428d1a7acSStefan Popa } 33528d1a7acSStefan Popa 33628d1a7acSStefan Popa static int ad5758_set_dc_dc_ilim(struct ad5758_state *st, unsigned int ilim) 33728d1a7acSStefan Popa { 33828d1a7acSStefan Popa int ret; 33928d1a7acSStefan Popa 34028d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG2, 34128d1a7acSStefan Popa AD5758_DCDC_CONFIG2_ILIMIT_MSK, 34228d1a7acSStefan Popa AD5758_DCDC_CONFIG2_ILIMIT_MODE(ilim)); 34328d1a7acSStefan Popa if (ret < 0) 34428d1a7acSStefan Popa return ret; 34528d1a7acSStefan Popa /* 34628d1a7acSStefan Popa * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. 34728d1a7acSStefan Popa * This allows the 3-wire interface communication to complete. 34828d1a7acSStefan Popa */ 34928d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, 35028d1a7acSStefan Popa AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); 35128d1a7acSStefan Popa } 35228d1a7acSStefan Popa 35328d1a7acSStefan Popa static int ad5758_slew_rate_set(struct ad5758_state *st, 35428d1a7acSStefan Popa unsigned int sr_clk_idx, 35528d1a7acSStefan Popa unsigned int sr_step_idx) 35628d1a7acSStefan Popa { 35728d1a7acSStefan Popa unsigned int mode; 35828d1a7acSStefan Popa unsigned long int mask; 35928d1a7acSStefan Popa int ret; 36028d1a7acSStefan Popa 36128d1a7acSStefan Popa mask = AD5758_DAC_CONFIG_SR_EN_MSK | 36228d1a7acSStefan Popa AD5758_DAC_CONFIG_SR_CLOCK_MSK | 36328d1a7acSStefan Popa AD5758_DAC_CONFIG_SR_STEP_MSK; 36428d1a7acSStefan Popa mode = AD5758_DAC_CONFIG_SR_EN_MODE(1) | 36528d1a7acSStefan Popa AD5758_DAC_CONFIG_SR_STEP_MODE(sr_step_idx) | 36628d1a7acSStefan Popa AD5758_DAC_CONFIG_SR_CLOCK_MODE(sr_clk_idx); 36728d1a7acSStefan Popa 36828d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, mask, mode); 36928d1a7acSStefan Popa if (ret < 0) 37028d1a7acSStefan Popa return ret; 37128d1a7acSStefan Popa 37228d1a7acSStefan Popa /* Wait to allow time for the internal calibrations to complete */ 37328d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 37428d1a7acSStefan Popa AD5758_CAL_MEM_UNREFRESHED_MSK); 37528d1a7acSStefan Popa } 37628d1a7acSStefan Popa 37728d1a7acSStefan Popa static int ad5758_slew_rate_config(struct ad5758_state *st) 37828d1a7acSStefan Popa { 37928d1a7acSStefan Popa unsigned int sr_clk_idx, sr_step_idx; 38028d1a7acSStefan Popa int i, res; 38128d1a7acSStefan Popa s64 diff_new, diff_old; 38228d1a7acSStefan Popa u64 sr_step, calc_slew_time; 38328d1a7acSStefan Popa 38428d1a7acSStefan Popa sr_clk_idx = 0; 38528d1a7acSStefan Popa sr_step_idx = 0; 38628d1a7acSStefan Popa diff_old = S64_MAX; 38728d1a7acSStefan Popa /* 38828d1a7acSStefan Popa * The slew time can be determined by using the formula: 38928d1a7acSStefan Popa * Slew Time = (Full Scale Out / (Step Size x Update Clk Freq)) 39028d1a7acSStefan Popa * where Slew time is expressed in microseconds 39128d1a7acSStefan Popa * Given the desired slew time, the following algorithm determines the 39228d1a7acSStefan Popa * best match for the step size and the update clock frequency. 39328d1a7acSStefan Popa */ 39428d1a7acSStefan Popa for (i = 0; i < ARRAY_SIZE(ad5758_sr_clk); i++) { 39528d1a7acSStefan Popa /* 39628d1a7acSStefan Popa * Go through each valid update clock freq and determine a raw 39728d1a7acSStefan Popa * value for the step size by using the formula: 39828d1a7acSStefan Popa * Step Size = Full Scale Out / (Update Clk Freq * Slew Time) 39928d1a7acSStefan Popa */ 40028d1a7acSStefan Popa sr_step = AD5758_FULL_SCALE_MICRO; 40128d1a7acSStefan Popa do_div(sr_step, ad5758_sr_clk[i]); 40228d1a7acSStefan Popa do_div(sr_step, st->slew_time); 40328d1a7acSStefan Popa /* 40428d1a7acSStefan Popa * After a raw value for step size was determined, find the 40528d1a7acSStefan Popa * closest valid match 40628d1a7acSStefan Popa */ 40728d1a7acSStefan Popa res = ad5758_find_closest_match(ad5758_sr_step, 40828d1a7acSStefan Popa ARRAY_SIZE(ad5758_sr_step), 40928d1a7acSStefan Popa sr_step); 41028d1a7acSStefan Popa /* Calculate the slew time */ 41128d1a7acSStefan Popa calc_slew_time = AD5758_FULL_SCALE_MICRO; 41228d1a7acSStefan Popa do_div(calc_slew_time, ad5758_sr_step[res]); 41328d1a7acSStefan Popa do_div(calc_slew_time, ad5758_sr_clk[i]); 41428d1a7acSStefan Popa /* 41528d1a7acSStefan Popa * Determine with how many microseconds the calculated slew time 41628d1a7acSStefan Popa * is different from the desired slew time and store the diff 41728d1a7acSStefan Popa * for the next iteration 41828d1a7acSStefan Popa */ 41928d1a7acSStefan Popa diff_new = abs(st->slew_time - calc_slew_time); 42028d1a7acSStefan Popa if (diff_new < diff_old) { 42128d1a7acSStefan Popa diff_old = diff_new; 42228d1a7acSStefan Popa sr_clk_idx = i; 42328d1a7acSStefan Popa sr_step_idx = res; 42428d1a7acSStefan Popa } 42528d1a7acSStefan Popa } 42628d1a7acSStefan Popa 42728d1a7acSStefan Popa return ad5758_slew_rate_set(st, sr_clk_idx, sr_step_idx); 42828d1a7acSStefan Popa } 42928d1a7acSStefan Popa 43028d1a7acSStefan Popa static int ad5758_set_out_range(struct ad5758_state *st, int range) 43128d1a7acSStefan Popa { 43228d1a7acSStefan Popa int ret; 43328d1a7acSStefan Popa 43428d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 43528d1a7acSStefan Popa AD5758_DAC_CONFIG_RANGE_MSK, 43628d1a7acSStefan Popa AD5758_DAC_CONFIG_RANGE_MODE(range)); 43728d1a7acSStefan Popa if (ret < 0) 43828d1a7acSStefan Popa return ret; 43928d1a7acSStefan Popa 44028d1a7acSStefan Popa /* Wait to allow time for the internal calibrations to complete */ 44128d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 44228d1a7acSStefan Popa AD5758_CAL_MEM_UNREFRESHED_MSK); 44328d1a7acSStefan Popa } 44428d1a7acSStefan Popa 44528d1a7acSStefan Popa static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable) 44628d1a7acSStefan Popa { 44728d1a7acSStefan Popa int ret; 44828d1a7acSStefan Popa 44928d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, 45028d1a7acSStefan Popa AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK, 45128d1a7acSStefan Popa AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable)); 45228d1a7acSStefan Popa if (ret < 0) 45328d1a7acSStefan Popa return ret; 45428d1a7acSStefan Popa /* 45528d1a7acSStefan Popa * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. 45628d1a7acSStefan Popa * This allows the 3-wire interface communication to complete. 45728d1a7acSStefan Popa */ 45828d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, 45928d1a7acSStefan Popa AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); 46028d1a7acSStefan Popa } 46128d1a7acSStefan Popa 46228d1a7acSStefan Popa static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) 46328d1a7acSStefan Popa { 46428d1a7acSStefan Popa int ret; 46528d1a7acSStefan Popa 46628d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 46728d1a7acSStefan Popa AD5758_DAC_CONFIG_INT_EN_MSK, 46828d1a7acSStefan Popa AD5758_DAC_CONFIG_INT_EN_MODE(enable)); 46928d1a7acSStefan Popa if (ret < 0) 47028d1a7acSStefan Popa return ret; 47128d1a7acSStefan Popa 47228d1a7acSStefan Popa /* Wait to allow time for the internal calibrations to complete */ 47328d1a7acSStefan Popa return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 47428d1a7acSStefan Popa AD5758_CAL_MEM_UNREFRESHED_MSK); 47528d1a7acSStefan Popa } 47628d1a7acSStefan Popa 47728d1a7acSStefan Popa static int ad5758_reg_access(struct iio_dev *indio_dev, 47828d1a7acSStefan Popa unsigned int reg, 47928d1a7acSStefan Popa unsigned int writeval, 48028d1a7acSStefan Popa unsigned int *readval) 48128d1a7acSStefan Popa { 48228d1a7acSStefan Popa struct ad5758_state *st = iio_priv(indio_dev); 48328d1a7acSStefan Popa int ret; 48428d1a7acSStefan Popa 48528d1a7acSStefan Popa mutex_lock(&st->lock); 48628d1a7acSStefan Popa if (readval) { 48728d1a7acSStefan Popa ret = ad5758_spi_reg_read(st, reg); 48828d1a7acSStefan Popa if (ret < 0) { 48928d1a7acSStefan Popa mutex_unlock(&st->lock); 49028d1a7acSStefan Popa return ret; 49128d1a7acSStefan Popa } 49228d1a7acSStefan Popa 49328d1a7acSStefan Popa *readval = ret; 49428d1a7acSStefan Popa ret = 0; 49528d1a7acSStefan Popa } else { 49628d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, reg, writeval); 49728d1a7acSStefan Popa } 49828d1a7acSStefan Popa mutex_unlock(&st->lock); 49928d1a7acSStefan Popa 50028d1a7acSStefan Popa return ret; 50128d1a7acSStefan Popa } 50228d1a7acSStefan Popa 50328d1a7acSStefan Popa static int ad5758_read_raw(struct iio_dev *indio_dev, 50428d1a7acSStefan Popa struct iio_chan_spec const *chan, 50528d1a7acSStefan Popa int *val, int *val2, long info) 50628d1a7acSStefan Popa { 50728d1a7acSStefan Popa struct ad5758_state *st = iio_priv(indio_dev); 50828d1a7acSStefan Popa int max, min, ret; 50928d1a7acSStefan Popa 51028d1a7acSStefan Popa switch (info) { 51128d1a7acSStefan Popa case IIO_CHAN_INFO_RAW: 51228d1a7acSStefan Popa mutex_lock(&st->lock); 51328d1a7acSStefan Popa ret = ad5758_spi_reg_read(st, AD5758_DAC_INPUT); 51428d1a7acSStefan Popa mutex_unlock(&st->lock); 51528d1a7acSStefan Popa if (ret < 0) 51628d1a7acSStefan Popa return ret; 51728d1a7acSStefan Popa 51828d1a7acSStefan Popa *val = ret; 51928d1a7acSStefan Popa return IIO_VAL_INT; 52028d1a7acSStefan Popa case IIO_CHAN_INFO_SCALE: 52128d1a7acSStefan Popa min = st->out_range.min; 52228d1a7acSStefan Popa max = st->out_range.max; 52328d1a7acSStefan Popa *val = (max - min) / 1000; 52428d1a7acSStefan Popa *val2 = 16; 52528d1a7acSStefan Popa return IIO_VAL_FRACTIONAL_LOG2; 52628d1a7acSStefan Popa case IIO_CHAN_INFO_OFFSET: 52728d1a7acSStefan Popa min = st->out_range.min; 52828d1a7acSStefan Popa max = st->out_range.max; 52928d1a7acSStefan Popa *val = ((min * (1 << 16)) / (max - min)) / 1000; 53028d1a7acSStefan Popa return IIO_VAL_INT; 53128d1a7acSStefan Popa default: 53228d1a7acSStefan Popa return -EINVAL; 53328d1a7acSStefan Popa } 53428d1a7acSStefan Popa } 53528d1a7acSStefan Popa 53628d1a7acSStefan Popa static int ad5758_write_raw(struct iio_dev *indio_dev, 53728d1a7acSStefan Popa struct iio_chan_spec const *chan, 53828d1a7acSStefan Popa int val, int val2, long info) 53928d1a7acSStefan Popa { 54028d1a7acSStefan Popa struct ad5758_state *st = iio_priv(indio_dev); 54128d1a7acSStefan Popa int ret; 54228d1a7acSStefan Popa 54328d1a7acSStefan Popa switch (info) { 54428d1a7acSStefan Popa case IIO_CHAN_INFO_RAW: 54528d1a7acSStefan Popa mutex_lock(&st->lock); 54628d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, AD5758_DAC_INPUT, val); 54728d1a7acSStefan Popa mutex_unlock(&st->lock); 54828d1a7acSStefan Popa return ret; 54928d1a7acSStefan Popa default: 55028d1a7acSStefan Popa return -EINVAL; 55128d1a7acSStefan Popa } 55228d1a7acSStefan Popa } 55328d1a7acSStefan Popa 55428d1a7acSStefan Popa static ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev, 55528d1a7acSStefan Popa uintptr_t priv, 55628d1a7acSStefan Popa const struct iio_chan_spec *chan, 55728d1a7acSStefan Popa char *buf) 55828d1a7acSStefan Popa { 55928d1a7acSStefan Popa struct ad5758_state *st = iio_priv(indio_dev); 56028d1a7acSStefan Popa 56128d1a7acSStefan Popa return sprintf(buf, "%d\n", st->pwr_down); 56228d1a7acSStefan Popa } 56328d1a7acSStefan Popa 56428d1a7acSStefan Popa static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, 56528d1a7acSStefan Popa uintptr_t priv, 56628d1a7acSStefan Popa struct iio_chan_spec const *chan, 56728d1a7acSStefan Popa const char *buf, size_t len) 56828d1a7acSStefan Popa { 56928d1a7acSStefan Popa struct ad5758_state *st = iio_priv(indio_dev); 57028d1a7acSStefan Popa bool pwr_down; 57128d1a7acSStefan Popa unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val; 57228d1a7acSStefan Popa unsigned long int dcdc_config1_msk, dac_config_msk; 57328d1a7acSStefan Popa int ret; 57428d1a7acSStefan Popa 57528d1a7acSStefan Popa ret = kstrtobool(buf, &pwr_down); 57628d1a7acSStefan Popa if (ret) 57728d1a7acSStefan Popa return ret; 57828d1a7acSStefan Popa 57928d1a7acSStefan Popa mutex_lock(&st->lock); 58028d1a7acSStefan Popa if (pwr_down) { 58128d1a7acSStefan Popa dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF; 58228d1a7acSStefan Popa val = 0; 58328d1a7acSStefan Popa } else { 58428d1a7acSStefan Popa dc_dc_mode = st->dc_dc_mode; 58528d1a7acSStefan Popa val = 1; 58628d1a7acSStefan Popa } 58728d1a7acSStefan Popa 58828d1a7acSStefan Popa dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) | 58928d1a7acSStefan Popa AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val); 59028d1a7acSStefan Popa dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK | 59128d1a7acSStefan Popa AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK; 59228d1a7acSStefan Popa 59328d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, 59428d1a7acSStefan Popa dcdc_config1_msk, 59528d1a7acSStefan Popa dcdc_config1_mode); 59628d1a7acSStefan Popa if (ret < 0) 59728d1a7acSStefan Popa goto err_unlock; 59828d1a7acSStefan Popa 59928d1a7acSStefan Popa dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | 60028d1a7acSStefan Popa AD5758_DAC_CONFIG_INT_EN_MODE(val); 60128d1a7acSStefan Popa dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK | 60228d1a7acSStefan Popa AD5758_DAC_CONFIG_INT_EN_MSK; 60328d1a7acSStefan Popa 60428d1a7acSStefan Popa ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 60528d1a7acSStefan Popa dac_config_msk, 60628d1a7acSStefan Popa dac_config_mode); 60728d1a7acSStefan Popa if (ret < 0) 60828d1a7acSStefan Popa goto err_unlock; 60928d1a7acSStefan Popa 61028d1a7acSStefan Popa st->pwr_down = pwr_down; 61128d1a7acSStefan Popa 61228d1a7acSStefan Popa err_unlock: 61328d1a7acSStefan Popa mutex_unlock(&st->lock); 61428d1a7acSStefan Popa 61528d1a7acSStefan Popa return ret ? ret : len; 61628d1a7acSStefan Popa } 61728d1a7acSStefan Popa 61828d1a7acSStefan Popa static const struct iio_info ad5758_info = { 61928d1a7acSStefan Popa .read_raw = ad5758_read_raw, 62028d1a7acSStefan Popa .write_raw = ad5758_write_raw, 62128d1a7acSStefan Popa .debugfs_reg_access = &ad5758_reg_access, 62228d1a7acSStefan Popa }; 62328d1a7acSStefan Popa 62428d1a7acSStefan Popa static const struct iio_chan_spec_ext_info ad5758_ext_info[] = { 62528d1a7acSStefan Popa { 62628d1a7acSStefan Popa .name = "powerdown", 62728d1a7acSStefan Popa .read = ad5758_read_powerdown, 62828d1a7acSStefan Popa .write = ad5758_write_powerdown, 62928d1a7acSStefan Popa .shared = IIO_SHARED_BY_TYPE, 63028d1a7acSStefan Popa }, 63128d1a7acSStefan Popa { } 63228d1a7acSStefan Popa }; 63328d1a7acSStefan Popa 63428d1a7acSStefan Popa #define AD5758_DAC_CHAN(_chan_type) { \ 63528d1a7acSStefan Popa .type = (_chan_type), \ 63628d1a7acSStefan Popa .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \ 63728d1a7acSStefan Popa BIT(IIO_CHAN_INFO_SCALE) | \ 63828d1a7acSStefan Popa BIT(IIO_CHAN_INFO_OFFSET), \ 63928d1a7acSStefan Popa .indexed = 1, \ 64028d1a7acSStefan Popa .output = 1, \ 64128d1a7acSStefan Popa .ext_info = ad5758_ext_info, \ 64228d1a7acSStefan Popa } 64328d1a7acSStefan Popa 64428d1a7acSStefan Popa static const struct iio_chan_spec ad5758_voltage_ch[] = { 64528d1a7acSStefan Popa AD5758_DAC_CHAN(IIO_VOLTAGE) 64628d1a7acSStefan Popa }; 64728d1a7acSStefan Popa 64828d1a7acSStefan Popa static const struct iio_chan_spec ad5758_current_ch[] = { 64928d1a7acSStefan Popa AD5758_DAC_CHAN(IIO_CURRENT) 65028d1a7acSStefan Popa }; 65128d1a7acSStefan Popa 65228d1a7acSStefan Popa static bool ad5758_is_valid_mode(enum ad5758_dc_dc_mode mode) 65328d1a7acSStefan Popa { 65428d1a7acSStefan Popa switch (mode) { 65528d1a7acSStefan Popa case AD5758_DCDC_MODE_DPC_CURRENT: 65628d1a7acSStefan Popa case AD5758_DCDC_MODE_DPC_VOLTAGE: 65728d1a7acSStefan Popa case AD5758_DCDC_MODE_PPC_CURRENT: 65828d1a7acSStefan Popa return true; 65928d1a7acSStefan Popa default: 66028d1a7acSStefan Popa return false; 66128d1a7acSStefan Popa } 66228d1a7acSStefan Popa } 66328d1a7acSStefan Popa 66428d1a7acSStefan Popa static int ad5758_crc_disable(struct ad5758_state *st) 66528d1a7acSStefan Popa { 66628d1a7acSStefan Popa unsigned int mask; 66728d1a7acSStefan Popa 66828d1a7acSStefan Popa mask = (AD5758_WR_FLAG_MSK(AD5758_DIGITAL_DIAG_CONFIG) << 24) | 0x5C3A; 66928d1a7acSStefan Popa st->d32[0] = cpu_to_be32(mask); 67028d1a7acSStefan Popa 67128d1a7acSStefan Popa return spi_write(st->spi, &st->d32[0], 4); 67228d1a7acSStefan Popa } 67328d1a7acSStefan Popa 67428d1a7acSStefan Popa static int ad5758_find_out_range(struct ad5758_state *st, 67528d1a7acSStefan Popa const struct ad5758_range *range, 67628d1a7acSStefan Popa unsigned int size, 67728d1a7acSStefan Popa int min, int max) 67828d1a7acSStefan Popa { 67928d1a7acSStefan Popa int i; 68028d1a7acSStefan Popa 68128d1a7acSStefan Popa for (i = 0; i < size; i++) { 68228d1a7acSStefan Popa if ((min == range[i].min) && (max == range[i].max)) { 68328d1a7acSStefan Popa st->out_range.reg = range[i].reg; 68428d1a7acSStefan Popa st->out_range.min = range[i].min; 68528d1a7acSStefan Popa st->out_range.max = range[i].max; 68628d1a7acSStefan Popa 68728d1a7acSStefan Popa return 0; 68828d1a7acSStefan Popa } 68928d1a7acSStefan Popa } 69028d1a7acSStefan Popa 69128d1a7acSStefan Popa return -EINVAL; 69228d1a7acSStefan Popa } 69328d1a7acSStefan Popa 69428d1a7acSStefan Popa static int ad5758_parse_dt(struct ad5758_state *st) 69528d1a7acSStefan Popa { 69628d1a7acSStefan Popa unsigned int tmp, tmparray[2], size; 69728d1a7acSStefan Popa const struct ad5758_range *range; 69828d1a7acSStefan Popa int *index, ret; 69928d1a7acSStefan Popa 70028d1a7acSStefan Popa st->dc_dc_ilim = 0; 70128d1a7acSStefan Popa ret = device_property_read_u32(&st->spi->dev, 70228d1a7acSStefan Popa "adi,dc-dc-ilim-microamp", &tmp); 70328d1a7acSStefan Popa if (ret) { 70428d1a7acSStefan Popa dev_dbg(&st->spi->dev, 70528d1a7acSStefan Popa "Missing \"dc-dc-ilim-microamp\" property\n"); 70628d1a7acSStefan Popa } else { 70728d1a7acSStefan Popa index = bsearch(&tmp, ad5758_dc_dc_ilim, 70828d1a7acSStefan Popa ARRAY_SIZE(ad5758_dc_dc_ilim), 70928d1a7acSStefan Popa sizeof(int), cmpfunc); 71028d1a7acSStefan Popa if (!index) 71128d1a7acSStefan Popa dev_dbg(&st->spi->dev, "dc-dc-ilim out of range\n"); 71228d1a7acSStefan Popa else 71328d1a7acSStefan Popa st->dc_dc_ilim = index - ad5758_dc_dc_ilim; 71428d1a7acSStefan Popa } 71528d1a7acSStefan Popa 71628d1a7acSStefan Popa ret = device_property_read_u32(&st->spi->dev, "adi,dc-dc-mode", 71728d1a7acSStefan Popa &st->dc_dc_mode); 71828d1a7acSStefan Popa if (ret) { 71928d1a7acSStefan Popa dev_err(&st->spi->dev, "Missing \"dc-dc-mode\" property\n"); 72028d1a7acSStefan Popa return ret; 72128d1a7acSStefan Popa } 72228d1a7acSStefan Popa 72328d1a7acSStefan Popa if (!ad5758_is_valid_mode(st->dc_dc_mode)) 72428d1a7acSStefan Popa return -EINVAL; 72528d1a7acSStefan Popa 72628d1a7acSStefan Popa if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) { 72728d1a7acSStefan Popa ret = device_property_read_u32_array(&st->spi->dev, 72828d1a7acSStefan Popa "adi,range-microvolt", 72928d1a7acSStefan Popa tmparray, 2); 73028d1a7acSStefan Popa if (ret) { 73128d1a7acSStefan Popa dev_err(&st->spi->dev, 73228d1a7acSStefan Popa "Missing \"range-microvolt\" property\n"); 73328d1a7acSStefan Popa return ret; 73428d1a7acSStefan Popa } 73528d1a7acSStefan Popa range = ad5758_voltage_range; 73628d1a7acSStefan Popa size = ARRAY_SIZE(ad5758_voltage_range); 73728d1a7acSStefan Popa } else { 73828d1a7acSStefan Popa ret = device_property_read_u32_array(&st->spi->dev, 73928d1a7acSStefan Popa "adi,range-microamp", 74028d1a7acSStefan Popa tmparray, 2); 74128d1a7acSStefan Popa if (ret) { 74228d1a7acSStefan Popa dev_err(&st->spi->dev, 74328d1a7acSStefan Popa "Missing \"range-microamp\" property\n"); 74428d1a7acSStefan Popa return ret; 74528d1a7acSStefan Popa } 74628d1a7acSStefan Popa range = ad5758_current_range; 74728d1a7acSStefan Popa size = ARRAY_SIZE(ad5758_current_range); 74828d1a7acSStefan Popa } 74928d1a7acSStefan Popa 75028d1a7acSStefan Popa ret = ad5758_find_out_range(st, range, size, tmparray[0], tmparray[1]); 75128d1a7acSStefan Popa if (ret) { 75228d1a7acSStefan Popa dev_err(&st->spi->dev, "range invalid\n"); 75328d1a7acSStefan Popa return ret; 75428d1a7acSStefan Popa } 75528d1a7acSStefan Popa 75628d1a7acSStefan Popa ret = device_property_read_u32(&st->spi->dev, "adi,slew-time-us", &tmp); 75728d1a7acSStefan Popa if (ret) { 75828d1a7acSStefan Popa dev_dbg(&st->spi->dev, "Missing \"slew-time-us\" property\n"); 75928d1a7acSStefan Popa st->slew_time = 0; 76028d1a7acSStefan Popa } else { 76128d1a7acSStefan Popa st->slew_time = tmp; 76228d1a7acSStefan Popa } 76328d1a7acSStefan Popa 76428d1a7acSStefan Popa return 0; 76528d1a7acSStefan Popa } 76628d1a7acSStefan Popa 76728d1a7acSStefan Popa static int ad5758_init(struct ad5758_state *st) 76828d1a7acSStefan Popa { 76928d1a7acSStefan Popa int regval, ret; 77028d1a7acSStefan Popa 77128d1a7acSStefan Popa /* Disable CRC checks */ 77228d1a7acSStefan Popa ret = ad5758_crc_disable(st); 77328d1a7acSStefan Popa if (ret < 0) 77428d1a7acSStefan Popa return ret; 77528d1a7acSStefan Popa 77628d1a7acSStefan Popa /* Perform a software reset */ 77728d1a7acSStefan Popa ret = ad5758_soft_reset(st); 77828d1a7acSStefan Popa if (ret < 0) 77928d1a7acSStefan Popa return ret; 78028d1a7acSStefan Popa 78128d1a7acSStefan Popa /* Disable CRC checks */ 78228d1a7acSStefan Popa ret = ad5758_crc_disable(st); 78328d1a7acSStefan Popa if (ret < 0) 78428d1a7acSStefan Popa return ret; 78528d1a7acSStefan Popa 78628d1a7acSStefan Popa /* Perform a calibration memory refresh */ 78728d1a7acSStefan Popa ret = ad5758_calib_mem_refresh(st); 78828d1a7acSStefan Popa if (ret < 0) 78928d1a7acSStefan Popa return ret; 79028d1a7acSStefan Popa 79128d1a7acSStefan Popa regval = ad5758_spi_reg_read(st, AD5758_DIGITAL_DIAG_RESULTS); 79228d1a7acSStefan Popa if (regval < 0) 79328d1a7acSStefan Popa return regval; 79428d1a7acSStefan Popa 79528d1a7acSStefan Popa /* Clear all the error flags */ 79628d1a7acSStefan Popa ret = ad5758_spi_reg_write(st, AD5758_DIGITAL_DIAG_RESULTS, regval); 79728d1a7acSStefan Popa if (ret < 0) 79828d1a7acSStefan Popa return ret; 79928d1a7acSStefan Popa 80028d1a7acSStefan Popa /* Set the dc-to-dc current limit */ 80128d1a7acSStefan Popa ret = ad5758_set_dc_dc_ilim(st, st->dc_dc_ilim); 80228d1a7acSStefan Popa if (ret < 0) 80328d1a7acSStefan Popa return ret; 80428d1a7acSStefan Popa 80528d1a7acSStefan Popa /* Configure the dc-to-dc controller mode */ 80628d1a7acSStefan Popa ret = ad5758_set_dc_dc_conv_mode(st, st->dc_dc_mode); 80728d1a7acSStefan Popa if (ret < 0) 80828d1a7acSStefan Popa return ret; 80928d1a7acSStefan Popa 81028d1a7acSStefan Popa /* Configure the output range */ 81128d1a7acSStefan Popa ret = ad5758_set_out_range(st, st->out_range.reg); 81228d1a7acSStefan Popa if (ret < 0) 81328d1a7acSStefan Popa return ret; 81428d1a7acSStefan Popa 81528d1a7acSStefan Popa /* Enable Slew Rate Control, set the slew rate clock and step */ 81628d1a7acSStefan Popa if (st->slew_time) { 81728d1a7acSStefan Popa ret = ad5758_slew_rate_config(st); 81828d1a7acSStefan Popa if (ret < 0) 81928d1a7acSStefan Popa return ret; 82028d1a7acSStefan Popa } 82128d1a7acSStefan Popa 82228d1a7acSStefan Popa /* Enable the VIOUT fault protection switch (FPS is closed) */ 82328d1a7acSStefan Popa ret = ad5758_fault_prot_switch_en(st, 1); 82428d1a7acSStefan Popa if (ret < 0) 82528d1a7acSStefan Popa return ret; 82628d1a7acSStefan Popa 82728d1a7acSStefan Popa /* Power up the DAC and internal (INT) amplifiers */ 82828d1a7acSStefan Popa ret = ad5758_internal_buffers_en(st, 1); 82928d1a7acSStefan Popa if (ret < 0) 83028d1a7acSStefan Popa return ret; 83128d1a7acSStefan Popa 83228d1a7acSStefan Popa /* Enable VIOUT */ 83328d1a7acSStefan Popa return ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 83428d1a7acSStefan Popa AD5758_DAC_CONFIG_OUT_EN_MSK, 83528d1a7acSStefan Popa AD5758_DAC_CONFIG_OUT_EN_MODE(1)); 83628d1a7acSStefan Popa } 83728d1a7acSStefan Popa 83828d1a7acSStefan Popa static int ad5758_probe(struct spi_device *spi) 83928d1a7acSStefan Popa { 84028d1a7acSStefan Popa struct ad5758_state *st; 84128d1a7acSStefan Popa struct iio_dev *indio_dev; 84228d1a7acSStefan Popa int ret; 84328d1a7acSStefan Popa 84428d1a7acSStefan Popa indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 84528d1a7acSStefan Popa if (!indio_dev) 84628d1a7acSStefan Popa return -ENOMEM; 84728d1a7acSStefan Popa 84828d1a7acSStefan Popa st = iio_priv(indio_dev); 84928d1a7acSStefan Popa spi_set_drvdata(spi, indio_dev); 85028d1a7acSStefan Popa 85128d1a7acSStefan Popa st->spi = spi; 85228d1a7acSStefan Popa 85328d1a7acSStefan Popa mutex_init(&st->lock); 85428d1a7acSStefan Popa 85528d1a7acSStefan Popa indio_dev->dev.parent = &spi->dev; 85628d1a7acSStefan Popa indio_dev->name = spi_get_device_id(spi)->name; 85728d1a7acSStefan Popa indio_dev->info = &ad5758_info; 85828d1a7acSStefan Popa indio_dev->modes = INDIO_DIRECT_MODE; 85928d1a7acSStefan Popa indio_dev->num_channels = 1; 86028d1a7acSStefan Popa 86128d1a7acSStefan Popa ret = ad5758_parse_dt(st); 86228d1a7acSStefan Popa if (ret < 0) 86328d1a7acSStefan Popa return ret; 86428d1a7acSStefan Popa 86528d1a7acSStefan Popa if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) 86628d1a7acSStefan Popa indio_dev->channels = ad5758_voltage_ch; 86728d1a7acSStefan Popa else 86828d1a7acSStefan Popa indio_dev->channels = ad5758_current_ch; 86928d1a7acSStefan Popa 87028d1a7acSStefan Popa ret = ad5758_init(st); 87128d1a7acSStefan Popa if (ret < 0) { 87228d1a7acSStefan Popa dev_err(&spi->dev, "AD5758 init failed\n"); 87328d1a7acSStefan Popa return ret; 87428d1a7acSStefan Popa } 87528d1a7acSStefan Popa 87628d1a7acSStefan Popa return devm_iio_device_register(&st->spi->dev, indio_dev); 87728d1a7acSStefan Popa } 87828d1a7acSStefan Popa 87928d1a7acSStefan Popa static const struct spi_device_id ad5758_id[] = { 88028d1a7acSStefan Popa { "ad5758", 0 }, 88128d1a7acSStefan Popa {} 88228d1a7acSStefan Popa }; 88328d1a7acSStefan Popa MODULE_DEVICE_TABLE(spi, ad5758_id); 88428d1a7acSStefan Popa 88528d1a7acSStefan Popa static struct spi_driver ad5758_driver = { 88628d1a7acSStefan Popa .driver = { 88728d1a7acSStefan Popa .name = KBUILD_MODNAME, 88828d1a7acSStefan Popa }, 88928d1a7acSStefan Popa .probe = ad5758_probe, 89028d1a7acSStefan Popa .id_table = ad5758_id, 89128d1a7acSStefan Popa }; 89228d1a7acSStefan Popa 89328d1a7acSStefan Popa module_spi_driver(ad5758_driver); 89428d1a7acSStefan Popa 89528d1a7acSStefan Popa MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); 89628d1a7acSStefan Popa MODULE_DESCRIPTION("Analog Devices AD5758 DAC"); 89728d1a7acSStefan Popa MODULE_LICENSE("GPL v2"); 898