18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5758 Digital to analog converters driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2018 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * TODO: Currently CRC is not supported in this driver 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/bsearch.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/property.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 208c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* AD5758 registers definition */ 238c2ecf20Sopenharmony_ci#define AD5758_NOP 0x00 248c2ecf20Sopenharmony_ci#define AD5758_DAC_INPUT 0x01 258c2ecf20Sopenharmony_ci#define AD5758_DAC_OUTPUT 0x02 268c2ecf20Sopenharmony_ci#define AD5758_CLEAR_CODE 0x03 278c2ecf20Sopenharmony_ci#define AD5758_USER_GAIN 0x04 288c2ecf20Sopenharmony_ci#define AD5758_USER_OFFSET 0x05 298c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG 0x06 308c2ecf20Sopenharmony_ci#define AD5758_SW_LDAC 0x07 318c2ecf20Sopenharmony_ci#define AD5758_KEY 0x08 328c2ecf20Sopenharmony_ci#define AD5758_GP_CONFIG1 0x09 338c2ecf20Sopenharmony_ci#define AD5758_GP_CONFIG2 0x0A 348c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG1 0x0B 358c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG2 0x0C 368c2ecf20Sopenharmony_ci#define AD5758_WDT_CONFIG 0x0F 378c2ecf20Sopenharmony_ci#define AD5758_DIGITAL_DIAG_CONFIG 0x10 388c2ecf20Sopenharmony_ci#define AD5758_ADC_CONFIG 0x11 398c2ecf20Sopenharmony_ci#define AD5758_FAULT_PIN_CONFIG 0x12 408c2ecf20Sopenharmony_ci#define AD5758_TWO_STAGE_READBACK_SELECT 0x13 418c2ecf20Sopenharmony_ci#define AD5758_DIGITAL_DIAG_RESULTS 0x14 428c2ecf20Sopenharmony_ci#define AD5758_ANALOG_DIAG_RESULTS 0x15 438c2ecf20Sopenharmony_ci#define AD5758_STATUS 0x16 448c2ecf20Sopenharmony_ci#define AD5758_CHIP_ID 0x17 458c2ecf20Sopenharmony_ci#define AD5758_FREQ_MONITOR 0x18 468c2ecf20Sopenharmony_ci#define AD5758_DEVICE_ID_0 0x19 478c2ecf20Sopenharmony_ci#define AD5758_DEVICE_ID_1 0x1A 488c2ecf20Sopenharmony_ci#define AD5758_DEVICE_ID_2 0x1B 498c2ecf20Sopenharmony_ci#define AD5758_DEVICE_ID_3 0x1C 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* AD5758_DAC_CONFIG */ 528c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_RANGE_MSK GENMASK(3, 0) 538c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_RANGE_MODE(x) (((x) & 0xF) << 0) 548c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_INT_EN_MSK BIT(5) 558c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_INT_EN_MODE(x) (((x) & 0x1) << 5) 568c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_OUT_EN_MSK BIT(6) 578c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_OUT_EN_MODE(x) (((x) & 0x1) << 6) 588c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_EN_MSK BIT(8) 598c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_EN_MODE(x) (((x) & 0x1) << 8) 608c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9) 618c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_CLOCK_MODE(x) (((x) & 0xF) << 9) 628c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13) 638c2ecf20Sopenharmony_ci#define AD5758_DAC_CONFIG_SR_STEP_MODE(x) (((x) & 0x7) << 13) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* AD5758_KEY */ 668c2ecf20Sopenharmony_ci#define AD5758_KEY_CODE_RESET_1 0x15FA 678c2ecf20Sopenharmony_ci#define AD5758_KEY_CODE_RESET_2 0xAF51 688c2ecf20Sopenharmony_ci#define AD5758_KEY_CODE_SINGLE_ADC_CONV 0x1ADC 698c2ecf20Sopenharmony_ci#define AD5758_KEY_CODE_RESET_WDT 0x0D06 708c2ecf20Sopenharmony_ci#define AD5758_KEY_CODE_CALIB_MEM_REFRESH 0xFCBA 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* AD5758_DCDC_CONFIG1 */ 738c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MSK GENMASK(4, 0) 748c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) 758c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) 768c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* AD5758_DCDC_CONFIG2 */ 798c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) 808c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG2_ILIMIT_MODE(x) (((x) & 0x7) << 1) 818c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG2_INTR_SAT_3WI_MSK BIT(11) 828c2ecf20Sopenharmony_ci#define AD5758_DCDC_CONFIG2_BUSY_3WI_MSK BIT(12) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* AD5758_DIGITAL_DIAG_RESULTS */ 858c2ecf20Sopenharmony_ci#define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* AD5758_ADC_CONFIG */ 888c2ecf20Sopenharmony_ci#define AD5758_ADC_CONFIG_PPC_BUF_EN(x) (((x) & 0x1) << 11) 898c2ecf20Sopenharmony_ci#define AD5758_ADC_CONFIG_PPC_BUF_MSK BIT(11) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define AD5758_FULL_SCALE_MICRO 65535000000ULL 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct ad5758_range { 968c2ecf20Sopenharmony_ci int reg; 978c2ecf20Sopenharmony_ci int min; 988c2ecf20Sopenharmony_ci int max; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/** 1028c2ecf20Sopenharmony_ci * struct ad5758_state - driver instance specific data 1038c2ecf20Sopenharmony_ci * @spi: spi_device 1048c2ecf20Sopenharmony_ci * @lock: mutex lock 1058c2ecf20Sopenharmony_ci * @gpio_reset: gpio descriptor for the reset line 1068c2ecf20Sopenharmony_ci * @out_range: struct which stores the output range 1078c2ecf20Sopenharmony_ci * @dc_dc_mode: variable which stores the mode of operation 1088c2ecf20Sopenharmony_ci * @dc_dc_ilim: variable which stores the dc-to-dc converter current limit 1098c2ecf20Sopenharmony_ci * @slew_time: variable which stores the target slew time 1108c2ecf20Sopenharmony_ci * @pwr_down: variable which contains whether a channel is powered down or not 1118c2ecf20Sopenharmony_ci * @d32: spi transfer buffers 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_cistruct ad5758_state { 1148c2ecf20Sopenharmony_ci struct spi_device *spi; 1158c2ecf20Sopenharmony_ci struct mutex lock; 1168c2ecf20Sopenharmony_ci struct gpio_desc *gpio_reset; 1178c2ecf20Sopenharmony_ci struct ad5758_range out_range; 1188c2ecf20Sopenharmony_ci unsigned int dc_dc_mode; 1198c2ecf20Sopenharmony_ci unsigned int dc_dc_ilim; 1208c2ecf20Sopenharmony_ci unsigned int slew_time; 1218c2ecf20Sopenharmony_ci bool pwr_down; 1228c2ecf20Sopenharmony_ci __be32 d32[3]; 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * Output ranges corresponding to bits [3:0] from DAC_CONFIG register 1278c2ecf20Sopenharmony_ci * 0000: 0 V to 5 V voltage range 1288c2ecf20Sopenharmony_ci * 0001: 0 V to 10 V voltage range 1298c2ecf20Sopenharmony_ci * 0010: ±5 V voltage range 1308c2ecf20Sopenharmony_ci * 0011: ±10 V voltage range 1318c2ecf20Sopenharmony_ci * 1000: 0 mA to 20 mA current range 1328c2ecf20Sopenharmony_ci * 1001: 0 mA to 24 mA current range 1338c2ecf20Sopenharmony_ci * 1010: 4 mA to 20 mA current range 1348c2ecf20Sopenharmony_ci * 1011: ±20 mA current range 1358c2ecf20Sopenharmony_ci * 1100: ±24 mA current range 1368c2ecf20Sopenharmony_ci * 1101: -1 mA to +22 mA current range 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_cienum ad5758_output_range { 1398c2ecf20Sopenharmony_ci AD5758_RANGE_0V_5V, 1408c2ecf20Sopenharmony_ci AD5758_RANGE_0V_10V, 1418c2ecf20Sopenharmony_ci AD5758_RANGE_PLUSMINUS_5V, 1428c2ecf20Sopenharmony_ci AD5758_RANGE_PLUSMINUS_10V, 1438c2ecf20Sopenharmony_ci AD5758_RANGE_0mA_20mA = 8, 1448c2ecf20Sopenharmony_ci AD5758_RANGE_0mA_24mA, 1458c2ecf20Sopenharmony_ci AD5758_RANGE_4mA_24mA, 1468c2ecf20Sopenharmony_ci AD5758_RANGE_PLUSMINUS_20mA, 1478c2ecf20Sopenharmony_ci AD5758_RANGE_PLUSMINUS_24mA, 1488c2ecf20Sopenharmony_ci AD5758_RANGE_MINUS_1mA_PLUS_22mA, 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cienum ad5758_dc_dc_mode { 1528c2ecf20Sopenharmony_ci AD5758_DCDC_MODE_POWER_OFF, 1538c2ecf20Sopenharmony_ci AD5758_DCDC_MODE_DPC_CURRENT, 1548c2ecf20Sopenharmony_ci AD5758_DCDC_MODE_DPC_VOLTAGE, 1558c2ecf20Sopenharmony_ci AD5758_DCDC_MODE_PPC_CURRENT, 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct ad5758_range ad5758_voltage_range[] = { 1598c2ecf20Sopenharmony_ci { AD5758_RANGE_0V_5V, 0, 5000000 }, 1608c2ecf20Sopenharmony_ci { AD5758_RANGE_0V_10V, 0, 10000000 }, 1618c2ecf20Sopenharmony_ci { AD5758_RANGE_PLUSMINUS_5V, -5000000, 5000000 }, 1628c2ecf20Sopenharmony_ci { AD5758_RANGE_PLUSMINUS_10V, -10000000, 10000000 } 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const struct ad5758_range ad5758_current_range[] = { 1668c2ecf20Sopenharmony_ci { AD5758_RANGE_0mA_20mA, 0, 20000}, 1678c2ecf20Sopenharmony_ci { AD5758_RANGE_0mA_24mA, 0, 24000 }, 1688c2ecf20Sopenharmony_ci { AD5758_RANGE_4mA_24mA, 4, 24000 }, 1698c2ecf20Sopenharmony_ci { AD5758_RANGE_PLUSMINUS_20mA, -20000, 20000 }, 1708c2ecf20Sopenharmony_ci { AD5758_RANGE_PLUSMINUS_24mA, -24000, 24000 }, 1718c2ecf20Sopenharmony_ci { AD5758_RANGE_MINUS_1mA_PLUS_22mA, -1000, 22000 }, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const int ad5758_sr_clk[16] = { 1758c2ecf20Sopenharmony_ci 240000, 200000, 150000, 128000, 64000, 32000, 16000, 8000, 4000, 2000, 1768c2ecf20Sopenharmony_ci 1000, 512, 256, 128, 64, 16 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const int ad5758_sr_step[8] = { 1808c2ecf20Sopenharmony_ci 4, 12, 64, 120, 256, 500, 1820, 2048 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const int ad5758_dc_dc_ilim[6] = { 1848c2ecf20Sopenharmony_ci 150000, 200000, 250000, 300000, 350000, 400000 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int ad5758_spi_reg_read(struct ad5758_state *st, unsigned int addr) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct spi_transfer t[] = { 1908c2ecf20Sopenharmony_ci { 1918c2ecf20Sopenharmony_ci .tx_buf = &st->d32[0], 1928c2ecf20Sopenharmony_ci .len = 4, 1938c2ecf20Sopenharmony_ci .cs_change = 1, 1948c2ecf20Sopenharmony_ci }, { 1958c2ecf20Sopenharmony_ci .tx_buf = &st->d32[1], 1968c2ecf20Sopenharmony_ci .rx_buf = &st->d32[2], 1978c2ecf20Sopenharmony_ci .len = 4, 1988c2ecf20Sopenharmony_ci }, 1998c2ecf20Sopenharmony_ci }; 2008c2ecf20Sopenharmony_ci int ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci st->d32[0] = cpu_to_be32( 2038c2ecf20Sopenharmony_ci (AD5758_WR_FLAG_MSK(AD5758_TWO_STAGE_READBACK_SELECT) << 24) | 2048c2ecf20Sopenharmony_ci (addr << 8)); 2058c2ecf20Sopenharmony_ci st->d32[1] = cpu_to_be32(AD5758_WR_FLAG_MSK(AD5758_NOP) << 24); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); 2088c2ecf20Sopenharmony_ci if (ret < 0) 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return (be32_to_cpu(st->d32[2]) >> 8) & 0xFFFF; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int ad5758_spi_reg_write(struct ad5758_state *st, 2158c2ecf20Sopenharmony_ci unsigned int addr, 2168c2ecf20Sopenharmony_ci unsigned int val) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci st->d32[0] = cpu_to_be32((AD5758_WR_FLAG_MSK(addr) << 24) | 2198c2ecf20Sopenharmony_ci ((val & 0xFFFF) << 8)); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return spi_write(st->spi, &st->d32[0], sizeof(st->d32[0])); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int ad5758_spi_write_mask(struct ad5758_state *st, 2258c2ecf20Sopenharmony_ci unsigned int addr, 2268c2ecf20Sopenharmony_ci unsigned long int mask, 2278c2ecf20Sopenharmony_ci unsigned int val) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci int regval; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci regval = ad5758_spi_reg_read(st, addr); 2328c2ecf20Sopenharmony_ci if (regval < 0) 2338c2ecf20Sopenharmony_ci return regval; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci regval &= ~mask; 2368c2ecf20Sopenharmony_ci regval |= val; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return ad5758_spi_reg_write(st, addr, regval); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int cmpfunc(const void *a, const void *b) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci return *(int *)a - *(int *)b; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int ad5758_find_closest_match(const int *array, 2478c2ecf20Sopenharmony_ci unsigned int size, int val) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 2528c2ecf20Sopenharmony_ci if (val <= array[i]) 2538c2ecf20Sopenharmony_ci return i; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return size - 1; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int ad5758_wait_for_task_complete(struct ad5758_state *st, 2608c2ecf20Sopenharmony_ci unsigned int reg, 2618c2ecf20Sopenharmony_ci unsigned int mask) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci unsigned int timeout; 2648c2ecf20Sopenharmony_ci int ret; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci timeout = 10; 2678c2ecf20Sopenharmony_ci do { 2688c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_read(st, reg); 2698c2ecf20Sopenharmony_ci if (ret < 0) 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (!(ret & mask)) 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci usleep_range(100, 1000); 2768c2ecf20Sopenharmony_ci } while (--timeout); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 2798c2ecf20Sopenharmony_ci "Error reading bit 0x%x in 0x%x register\n", mask, reg); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return -EIO; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int ad5758_calib_mem_refresh(struct ad5758_state *st) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci int ret; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, AD5758_KEY, 2898c2ecf20Sopenharmony_ci AD5758_KEY_CODE_CALIB_MEM_REFRESH); 2908c2ecf20Sopenharmony_ci if (ret < 0) { 2918c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 2928c2ecf20Sopenharmony_ci "Failed to initiate a calibration memory refresh\n"); 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Wait to allow time for the internal calibrations to complete */ 2978c2ecf20Sopenharmony_ci return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 2988c2ecf20Sopenharmony_ci AD5758_CAL_MEM_UNREFRESHED_MSK); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int ad5758_soft_reset(struct ad5758_state *st) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci int ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_1); 3068c2ecf20Sopenharmony_ci if (ret < 0) 3078c2ecf20Sopenharmony_ci return ret; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_2); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Perform a software reset and wait at least 100us */ 3128c2ecf20Sopenharmony_ci usleep_range(100, 1000); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st, 3188c2ecf20Sopenharmony_ci enum ad5758_dc_dc_mode mode) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci int ret; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * The ENABLE_PPC_BUFFERS bit must be set prior to enabling PPC current 3248c2ecf20Sopenharmony_ci * mode. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci if (mode == AD5758_DCDC_MODE_PPC_CURRENT) { 3278c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_ADC_CONFIG, 3288c2ecf20Sopenharmony_ci AD5758_ADC_CONFIG_PPC_BUF_MSK, 3298c2ecf20Sopenharmony_ci AD5758_ADC_CONFIG_PPC_BUF_EN(1)); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, 3358c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, 3368c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); 3378c2ecf20Sopenharmony_ci if (ret < 0) 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* 3418c2ecf20Sopenharmony_ci * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. 3428c2ecf20Sopenharmony_ci * This allows the 3-wire interface communication to complete. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci ret = ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, 3458c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); 3468c2ecf20Sopenharmony_ci if (ret < 0) 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci st->dc_dc_mode = mode; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int ad5758_set_dc_dc_ilim(struct ad5758_state *st, unsigned int ilim) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci int ret; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG2, 3598c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG2_ILIMIT_MSK, 3608c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG2_ILIMIT_MODE(ilim)); 3618c2ecf20Sopenharmony_ci if (ret < 0) 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. 3658c2ecf20Sopenharmony_ci * This allows the 3-wire interface communication to complete. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, 3688c2ecf20Sopenharmony_ci AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int ad5758_slew_rate_set(struct ad5758_state *st, 3728c2ecf20Sopenharmony_ci unsigned int sr_clk_idx, 3738c2ecf20Sopenharmony_ci unsigned int sr_step_idx) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci unsigned int mode; 3768c2ecf20Sopenharmony_ci unsigned long int mask; 3778c2ecf20Sopenharmony_ci int ret; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci mask = AD5758_DAC_CONFIG_SR_EN_MSK | 3808c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_SR_CLOCK_MSK | 3818c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_SR_STEP_MSK; 3828c2ecf20Sopenharmony_ci mode = AD5758_DAC_CONFIG_SR_EN_MODE(1) | 3838c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_SR_STEP_MODE(sr_step_idx) | 3848c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_SR_CLOCK_MODE(sr_clk_idx); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, mask, mode); 3878c2ecf20Sopenharmony_ci if (ret < 0) 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Wait to allow time for the internal calibrations to complete */ 3918c2ecf20Sopenharmony_ci return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 3928c2ecf20Sopenharmony_ci AD5758_CAL_MEM_UNREFRESHED_MSK); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int ad5758_slew_rate_config(struct ad5758_state *st) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci unsigned int sr_clk_idx, sr_step_idx; 3988c2ecf20Sopenharmony_ci int i, res; 3998c2ecf20Sopenharmony_ci s64 diff_new, diff_old; 4008c2ecf20Sopenharmony_ci u64 sr_step, calc_slew_time; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci sr_clk_idx = 0; 4038c2ecf20Sopenharmony_ci sr_step_idx = 0; 4048c2ecf20Sopenharmony_ci diff_old = S64_MAX; 4058c2ecf20Sopenharmony_ci /* 4068c2ecf20Sopenharmony_ci * The slew time can be determined by using the formula: 4078c2ecf20Sopenharmony_ci * Slew Time = (Full Scale Out / (Step Size x Update Clk Freq)) 4088c2ecf20Sopenharmony_ci * where Slew time is expressed in microseconds 4098c2ecf20Sopenharmony_ci * Given the desired slew time, the following algorithm determines the 4108c2ecf20Sopenharmony_ci * best match for the step size and the update clock frequency. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ad5758_sr_clk); i++) { 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * Go through each valid update clock freq and determine a raw 4158c2ecf20Sopenharmony_ci * value for the step size by using the formula: 4168c2ecf20Sopenharmony_ci * Step Size = Full Scale Out / (Update Clk Freq * Slew Time) 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci sr_step = AD5758_FULL_SCALE_MICRO; 4198c2ecf20Sopenharmony_ci do_div(sr_step, ad5758_sr_clk[i]); 4208c2ecf20Sopenharmony_ci do_div(sr_step, st->slew_time); 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * After a raw value for step size was determined, find the 4238c2ecf20Sopenharmony_ci * closest valid match 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci res = ad5758_find_closest_match(ad5758_sr_step, 4268c2ecf20Sopenharmony_ci ARRAY_SIZE(ad5758_sr_step), 4278c2ecf20Sopenharmony_ci sr_step); 4288c2ecf20Sopenharmony_ci /* Calculate the slew time */ 4298c2ecf20Sopenharmony_ci calc_slew_time = AD5758_FULL_SCALE_MICRO; 4308c2ecf20Sopenharmony_ci do_div(calc_slew_time, ad5758_sr_step[res]); 4318c2ecf20Sopenharmony_ci do_div(calc_slew_time, ad5758_sr_clk[i]); 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * Determine with how many microseconds the calculated slew time 4348c2ecf20Sopenharmony_ci * is different from the desired slew time and store the diff 4358c2ecf20Sopenharmony_ci * for the next iteration 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci diff_new = abs(st->slew_time - calc_slew_time); 4388c2ecf20Sopenharmony_ci if (diff_new < diff_old) { 4398c2ecf20Sopenharmony_ci diff_old = diff_new; 4408c2ecf20Sopenharmony_ci sr_clk_idx = i; 4418c2ecf20Sopenharmony_ci sr_step_idx = res; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return ad5758_slew_rate_set(st, sr_clk_idx, sr_step_idx); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int ad5758_set_out_range(struct ad5758_state *st, int range) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci int ret; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 4538c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_RANGE_MSK, 4548c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_RANGE_MODE(range)); 4558c2ecf20Sopenharmony_ci if (ret < 0) 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Wait to allow time for the internal calibrations to complete */ 4598c2ecf20Sopenharmony_ci return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 4608c2ecf20Sopenharmony_ci AD5758_CAL_MEM_UNREFRESHED_MSK); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int ret; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 4688c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_INT_EN_MSK, 4698c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_INT_EN_MODE(enable)); 4708c2ecf20Sopenharmony_ci if (ret < 0) 4718c2ecf20Sopenharmony_ci return ret; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Wait to allow time for the internal calibrations to complete */ 4748c2ecf20Sopenharmony_ci return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, 4758c2ecf20Sopenharmony_ci AD5758_CAL_MEM_UNREFRESHED_MSK); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int ad5758_reset(struct ad5758_state *st) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci if (st->gpio_reset) { 4818c2ecf20Sopenharmony_ci gpiod_set_value(st->gpio_reset, 0); 4828c2ecf20Sopenharmony_ci usleep_range(100, 1000); 4838c2ecf20Sopenharmony_ci gpiod_set_value(st->gpio_reset, 1); 4848c2ecf20Sopenharmony_ci usleep_range(100, 1000); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci } else { 4888c2ecf20Sopenharmony_ci /* Perform a software reset */ 4898c2ecf20Sopenharmony_ci return ad5758_soft_reset(st); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int ad5758_reg_access(struct iio_dev *indio_dev, 4948c2ecf20Sopenharmony_ci unsigned int reg, 4958c2ecf20Sopenharmony_ci unsigned int writeval, 4968c2ecf20Sopenharmony_ci unsigned int *readval) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct ad5758_state *st = iio_priv(indio_dev); 4998c2ecf20Sopenharmony_ci int ret; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 5028c2ecf20Sopenharmony_ci if (readval) { 5038c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_read(st, reg); 5048c2ecf20Sopenharmony_ci if (ret < 0) { 5058c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 5068c2ecf20Sopenharmony_ci return ret; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci *readval = ret; 5108c2ecf20Sopenharmony_ci ret = 0; 5118c2ecf20Sopenharmony_ci } else { 5128c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, reg, writeval); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return ret; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int ad5758_read_raw(struct iio_dev *indio_dev, 5208c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 5218c2ecf20Sopenharmony_ci int *val, int *val2, long info) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct ad5758_state *st = iio_priv(indio_dev); 5248c2ecf20Sopenharmony_ci int max, min, ret; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci switch (info) { 5278c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 5288c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 5298c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_read(st, AD5758_DAC_INPUT); 5308c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 5318c2ecf20Sopenharmony_ci if (ret < 0) 5328c2ecf20Sopenharmony_ci return ret; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci *val = ret; 5358c2ecf20Sopenharmony_ci return IIO_VAL_INT; 5368c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 5378c2ecf20Sopenharmony_ci min = st->out_range.min; 5388c2ecf20Sopenharmony_ci max = st->out_range.max; 5398c2ecf20Sopenharmony_ci *val = (max - min) / 1000; 5408c2ecf20Sopenharmony_ci *val2 = 16; 5418c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 5428c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 5438c2ecf20Sopenharmony_ci min = st->out_range.min; 5448c2ecf20Sopenharmony_ci max = st->out_range.max; 5458c2ecf20Sopenharmony_ci *val = ((min * (1 << 16)) / (max - min)) / 1000; 5468c2ecf20Sopenharmony_ci return IIO_VAL_INT; 5478c2ecf20Sopenharmony_ci default: 5488c2ecf20Sopenharmony_ci return -EINVAL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int ad5758_write_raw(struct iio_dev *indio_dev, 5538c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 5548c2ecf20Sopenharmony_ci int val, int val2, long info) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct ad5758_state *st = iio_priv(indio_dev); 5578c2ecf20Sopenharmony_ci int ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci switch (info) { 5608c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 5618c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 5628c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, AD5758_DAC_INPUT, val); 5638c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 5648c2ecf20Sopenharmony_ci return ret; 5658c2ecf20Sopenharmony_ci default: 5668c2ecf20Sopenharmony_ci return -EINVAL; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev, 5718c2ecf20Sopenharmony_ci uintptr_t priv, 5728c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 5738c2ecf20Sopenharmony_ci char *buf) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct ad5758_state *st = iio_priv(indio_dev); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", st->pwr_down); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, 5818c2ecf20Sopenharmony_ci uintptr_t priv, 5828c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 5838c2ecf20Sopenharmony_ci const char *buf, size_t len) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct ad5758_state *st = iio_priv(indio_dev); 5868c2ecf20Sopenharmony_ci bool pwr_down; 5878c2ecf20Sopenharmony_ci unsigned int dac_config_mode, val; 5888c2ecf20Sopenharmony_ci unsigned long int dac_config_msk; 5898c2ecf20Sopenharmony_ci int ret; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci ret = kstrtobool(buf, &pwr_down); 5928c2ecf20Sopenharmony_ci if (ret) 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 5968c2ecf20Sopenharmony_ci if (pwr_down) 5978c2ecf20Sopenharmony_ci val = 0; 5988c2ecf20Sopenharmony_ci else 5998c2ecf20Sopenharmony_ci val = 1; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | 6028c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_INT_EN_MODE(val); 6038c2ecf20Sopenharmony_ci dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK | 6048c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_INT_EN_MSK; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 6078c2ecf20Sopenharmony_ci dac_config_msk, 6088c2ecf20Sopenharmony_ci dac_config_mode); 6098c2ecf20Sopenharmony_ci if (ret < 0) 6108c2ecf20Sopenharmony_ci goto err_unlock; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci st->pwr_down = pwr_down; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cierr_unlock: 6158c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return ret ? ret : len; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic const struct iio_info ad5758_info = { 6218c2ecf20Sopenharmony_ci .read_raw = ad5758_read_raw, 6228c2ecf20Sopenharmony_ci .write_raw = ad5758_write_raw, 6238c2ecf20Sopenharmony_ci .debugfs_reg_access = &ad5758_reg_access, 6248c2ecf20Sopenharmony_ci}; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5758_ext_info[] = { 6278c2ecf20Sopenharmony_ci { 6288c2ecf20Sopenharmony_ci .name = "powerdown", 6298c2ecf20Sopenharmony_ci .read = ad5758_read_powerdown, 6308c2ecf20Sopenharmony_ci .write = ad5758_write_powerdown, 6318c2ecf20Sopenharmony_ci .shared = IIO_SHARED_BY_TYPE, 6328c2ecf20Sopenharmony_ci }, 6338c2ecf20Sopenharmony_ci { } 6348c2ecf20Sopenharmony_ci}; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci#define AD5758_DAC_CHAN(_chan_type) { \ 6378c2ecf20Sopenharmony_ci .type = (_chan_type), \ 6388c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \ 6398c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 6408c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 6418c2ecf20Sopenharmony_ci .indexed = 1, \ 6428c2ecf20Sopenharmony_ci .output = 1, \ 6438c2ecf20Sopenharmony_ci .ext_info = ad5758_ext_info, \ 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic const struct iio_chan_spec ad5758_voltage_ch[] = { 6478c2ecf20Sopenharmony_ci AD5758_DAC_CHAN(IIO_VOLTAGE) 6488c2ecf20Sopenharmony_ci}; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic const struct iio_chan_spec ad5758_current_ch[] = { 6518c2ecf20Sopenharmony_ci AD5758_DAC_CHAN(IIO_CURRENT) 6528c2ecf20Sopenharmony_ci}; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic bool ad5758_is_valid_mode(enum ad5758_dc_dc_mode mode) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci switch (mode) { 6578c2ecf20Sopenharmony_ci case AD5758_DCDC_MODE_DPC_CURRENT: 6588c2ecf20Sopenharmony_ci case AD5758_DCDC_MODE_DPC_VOLTAGE: 6598c2ecf20Sopenharmony_ci case AD5758_DCDC_MODE_PPC_CURRENT: 6608c2ecf20Sopenharmony_ci return true; 6618c2ecf20Sopenharmony_ci default: 6628c2ecf20Sopenharmony_ci return false; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int ad5758_crc_disable(struct ad5758_state *st) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci unsigned int mask; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci mask = (AD5758_WR_FLAG_MSK(AD5758_DIGITAL_DIAG_CONFIG) << 24) | 0x5C3A; 6718c2ecf20Sopenharmony_ci st->d32[0] = cpu_to_be32(mask); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return spi_write(st->spi, &st->d32[0], 4); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int ad5758_find_out_range(struct ad5758_state *st, 6778c2ecf20Sopenharmony_ci const struct ad5758_range *range, 6788c2ecf20Sopenharmony_ci unsigned int size, 6798c2ecf20Sopenharmony_ci int min, int max) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci int i; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 6848c2ecf20Sopenharmony_ci if ((min == range[i].min) && (max == range[i].max)) { 6858c2ecf20Sopenharmony_ci st->out_range.reg = range[i].reg; 6868c2ecf20Sopenharmony_ci st->out_range.min = range[i].min; 6878c2ecf20Sopenharmony_ci st->out_range.max = range[i].max; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic int ad5758_parse_dt(struct ad5758_state *st) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned int tmp, tmparray[2], size; 6998c2ecf20Sopenharmony_ci const struct ad5758_range *range; 7008c2ecf20Sopenharmony_ci int *index, ret; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci st->dc_dc_ilim = 0; 7038c2ecf20Sopenharmony_ci ret = device_property_read_u32(&st->spi->dev, 7048c2ecf20Sopenharmony_ci "adi,dc-dc-ilim-microamp", &tmp); 7058c2ecf20Sopenharmony_ci if (ret) { 7068c2ecf20Sopenharmony_ci dev_dbg(&st->spi->dev, 7078c2ecf20Sopenharmony_ci "Missing \"dc-dc-ilim-microamp\" property\n"); 7088c2ecf20Sopenharmony_ci } else { 7098c2ecf20Sopenharmony_ci index = bsearch(&tmp, ad5758_dc_dc_ilim, 7108c2ecf20Sopenharmony_ci ARRAY_SIZE(ad5758_dc_dc_ilim), 7118c2ecf20Sopenharmony_ci sizeof(int), cmpfunc); 7128c2ecf20Sopenharmony_ci if (!index) 7138c2ecf20Sopenharmony_ci dev_dbg(&st->spi->dev, "dc-dc-ilim out of range\n"); 7148c2ecf20Sopenharmony_ci else 7158c2ecf20Sopenharmony_ci st->dc_dc_ilim = index - ad5758_dc_dc_ilim; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ret = device_property_read_u32(&st->spi->dev, "adi,dc-dc-mode", 7198c2ecf20Sopenharmony_ci &st->dc_dc_mode); 7208c2ecf20Sopenharmony_ci if (ret) { 7218c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, "Missing \"dc-dc-mode\" property\n"); 7228c2ecf20Sopenharmony_ci return ret; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (!ad5758_is_valid_mode(st->dc_dc_mode)) 7268c2ecf20Sopenharmony_ci return -EINVAL; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) { 7298c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(&st->spi->dev, 7308c2ecf20Sopenharmony_ci "adi,range-microvolt", 7318c2ecf20Sopenharmony_ci tmparray, 2); 7328c2ecf20Sopenharmony_ci if (ret) { 7338c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 7348c2ecf20Sopenharmony_ci "Missing \"range-microvolt\" property\n"); 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci range = ad5758_voltage_range; 7388c2ecf20Sopenharmony_ci size = ARRAY_SIZE(ad5758_voltage_range); 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci ret = device_property_read_u32_array(&st->spi->dev, 7418c2ecf20Sopenharmony_ci "adi,range-microamp", 7428c2ecf20Sopenharmony_ci tmparray, 2); 7438c2ecf20Sopenharmony_ci if (ret) { 7448c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, 7458c2ecf20Sopenharmony_ci "Missing \"range-microamp\" property\n"); 7468c2ecf20Sopenharmony_ci return ret; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci range = ad5758_current_range; 7498c2ecf20Sopenharmony_ci size = ARRAY_SIZE(ad5758_current_range); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci ret = ad5758_find_out_range(st, range, size, tmparray[0], tmparray[1]); 7538c2ecf20Sopenharmony_ci if (ret) { 7548c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, "range invalid\n"); 7558c2ecf20Sopenharmony_ci return ret; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci ret = device_property_read_u32(&st->spi->dev, "adi,slew-time-us", &tmp); 7598c2ecf20Sopenharmony_ci if (ret) { 7608c2ecf20Sopenharmony_ci dev_dbg(&st->spi->dev, "Missing \"slew-time-us\" property\n"); 7618c2ecf20Sopenharmony_ci st->slew_time = 0; 7628c2ecf20Sopenharmony_ci } else { 7638c2ecf20Sopenharmony_ci st->slew_time = tmp; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int ad5758_init(struct ad5758_state *st) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci int regval, ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", 7748c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 7758c2ecf20Sopenharmony_ci if (IS_ERR(st->gpio_reset)) 7768c2ecf20Sopenharmony_ci return PTR_ERR(st->gpio_reset); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Disable CRC checks */ 7798c2ecf20Sopenharmony_ci ret = ad5758_crc_disable(st); 7808c2ecf20Sopenharmony_ci if (ret < 0) 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* Perform a reset */ 7848c2ecf20Sopenharmony_ci ret = ad5758_reset(st); 7858c2ecf20Sopenharmony_ci if (ret < 0) 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Disable CRC checks */ 7898c2ecf20Sopenharmony_ci ret = ad5758_crc_disable(st); 7908c2ecf20Sopenharmony_ci if (ret < 0) 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Perform a calibration memory refresh */ 7948c2ecf20Sopenharmony_ci ret = ad5758_calib_mem_refresh(st); 7958c2ecf20Sopenharmony_ci if (ret < 0) 7968c2ecf20Sopenharmony_ci return ret; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci regval = ad5758_spi_reg_read(st, AD5758_DIGITAL_DIAG_RESULTS); 7998c2ecf20Sopenharmony_ci if (regval < 0) 8008c2ecf20Sopenharmony_ci return regval; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* Clear all the error flags */ 8038c2ecf20Sopenharmony_ci ret = ad5758_spi_reg_write(st, AD5758_DIGITAL_DIAG_RESULTS, regval); 8048c2ecf20Sopenharmony_ci if (ret < 0) 8058c2ecf20Sopenharmony_ci return ret; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Set the dc-to-dc current limit */ 8088c2ecf20Sopenharmony_ci ret = ad5758_set_dc_dc_ilim(st, st->dc_dc_ilim); 8098c2ecf20Sopenharmony_ci if (ret < 0) 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* Configure the dc-to-dc controller mode */ 8138c2ecf20Sopenharmony_ci ret = ad5758_set_dc_dc_conv_mode(st, st->dc_dc_mode); 8148c2ecf20Sopenharmony_ci if (ret < 0) 8158c2ecf20Sopenharmony_ci return ret; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Configure the output range */ 8188c2ecf20Sopenharmony_ci ret = ad5758_set_out_range(st, st->out_range.reg); 8198c2ecf20Sopenharmony_ci if (ret < 0) 8208c2ecf20Sopenharmony_ci return ret; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* Enable Slew Rate Control, set the slew rate clock and step */ 8238c2ecf20Sopenharmony_ci if (st->slew_time) { 8248c2ecf20Sopenharmony_ci ret = ad5758_slew_rate_config(st); 8258c2ecf20Sopenharmony_ci if (ret < 0) 8268c2ecf20Sopenharmony_ci return ret; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Power up the DAC and internal (INT) amplifiers */ 8308c2ecf20Sopenharmony_ci ret = ad5758_internal_buffers_en(st, 1); 8318c2ecf20Sopenharmony_ci if (ret < 0) 8328c2ecf20Sopenharmony_ci return ret; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Enable VIOUT */ 8358c2ecf20Sopenharmony_ci return ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, 8368c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_OUT_EN_MSK, 8378c2ecf20Sopenharmony_ci AD5758_DAC_CONFIG_OUT_EN_MODE(1)); 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int ad5758_probe(struct spi_device *spi) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct ad5758_state *st; 8438c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 8448c2ecf20Sopenharmony_ci int ret; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 8478c2ecf20Sopenharmony_ci if (!indio_dev) 8488c2ecf20Sopenharmony_ci return -ENOMEM; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 8518c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci st->spi = spi; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci mutex_init(&st->lock); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci indio_dev->name = spi_get_device_id(spi)->name; 8588c2ecf20Sopenharmony_ci indio_dev->info = &ad5758_info; 8598c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 8608c2ecf20Sopenharmony_ci indio_dev->num_channels = 1; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci ret = ad5758_parse_dt(st); 8638c2ecf20Sopenharmony_ci if (ret < 0) 8648c2ecf20Sopenharmony_ci return ret; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) 8678c2ecf20Sopenharmony_ci indio_dev->channels = ad5758_voltage_ch; 8688c2ecf20Sopenharmony_ci else 8698c2ecf20Sopenharmony_ci indio_dev->channels = ad5758_current_ch; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ret = ad5758_init(st); 8728c2ecf20Sopenharmony_ci if (ret < 0) { 8738c2ecf20Sopenharmony_ci dev_err(&spi->dev, "AD5758 init failed\n"); 8748c2ecf20Sopenharmony_ci return ret; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return devm_iio_device_register(&st->spi->dev, indio_dev); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5758_id[] = { 8818c2ecf20Sopenharmony_ci { "ad5758", 0 }, 8828c2ecf20Sopenharmony_ci {} 8838c2ecf20Sopenharmony_ci}; 8848c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5758_id); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic const struct of_device_id ad5758_of_match[] = { 8878c2ecf20Sopenharmony_ci { .compatible = "adi,ad5758" }, 8888c2ecf20Sopenharmony_ci { }, 8898c2ecf20Sopenharmony_ci}; 8908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ad5758_of_match); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic struct spi_driver ad5758_driver = { 8938c2ecf20Sopenharmony_ci .driver = { 8948c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 8958c2ecf20Sopenharmony_ci .of_match_table = ad5758_of_match, 8968c2ecf20Sopenharmony_ci }, 8978c2ecf20Sopenharmony_ci .probe = ad5758_probe, 8988c2ecf20Sopenharmony_ci .id_table = ad5758_id, 8998c2ecf20Sopenharmony_ci}; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cimodule_spi_driver(ad5758_driver); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); 9048c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5758 DAC"); 9058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 906