// SPDX-License-Identifier: GPL-2.0 /* * AD8460 Waveform generator DAC Driver * * Copyright (C) 2024 Analog Devices, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define AD8460_CTRL_REG(x) (x) #define AD8460_HVDAC_DATA_WORD(x) (0x60 + (2 * (x))) #define AD8460_HV_RESET_MSK BIT(7) #define AD8460_HV_SLEEP_MSK BIT(4) #define AD8460_WAVE_GEN_MODE_MSK BIT(0) #define AD8460_HVDAC_SLEEP_MSK BIT(3) #define AD8460_FAULT_ARM_MSK BIT(7) #define AD8460_FAULT_LIMIT_MSK GENMASK(6, 0) #define AD8460_APG_MODE_ENABLE_MSK BIT(5) #define AD8460_PATTERN_DEPTH_MSK GENMASK(3, 0) #define AD8460_QUIESCENT_CURRENT_MSK GENMASK(7, 0) #define AD8460_SHUTDOWN_FLAG_MSK BIT(7) #define AD8460_DATA_BYTE_LOW_MSK GENMASK(7, 0) #define AD8460_DATA_BYTE_HIGH_MSK GENMASK(5, 0) #define AD8460_DATA_BYTE_FULL_MSK GENMASK(13, 0) #define AD8460_DEFAULT_FAULT_PROTECT 0x00 #define AD8460_DATA_BYTE_WORD_LENGTH 2 #define AD8460_NUM_DATA_WORDS 16 #define AD8460_NOMINAL_VOLTAGE_SPAN 80 #define AD8460_MIN_EXT_RESISTOR_OHMS 2000 #define AD8460_MAX_EXT_RESISTOR_OHMS 20000 #define AD8460_MIN_VREFIO_UV 120000 #define AD8460_MAX_VREFIO_UV 1200000 #define AD8460_ABS_MAX_OVERVOLTAGE_UV 55000000 #define AD8460_ABS_MAX_OVERCURRENT_UA 1000000 #define AD8460_MAX_OVERTEMPERATURE_MC 150000 #define AD8460_MIN_OVERTEMPERATURE_MC 20000 #define AD8460_CURRENT_LIMIT_CONV(x) ((x) / 15625) #define AD8460_VOLTAGE_LIMIT_CONV(x) ((x) / 1953000) #define AD8460_TEMP_LIMIT_CONV(x) (((x) + 266640) / 6510) enum ad8460_fault_type { AD8460_OVERCURRENT_SRC, AD8460_OVERCURRENT_SNK, AD8460_OVERVOLTAGE_POS, AD8460_OVERVOLTAGE_NEG, AD8460_OVERTEMPERATURE, }; struct ad8460_state { struct spi_device *spi; struct regmap *regmap; struct iio_channel *tmp_adc_channel; struct clk *sync_clk; /* lock to protect against multiple access to the device and shared data */ struct mutex lock; int refio_1p2v_mv; u32 ext_resistor_ohms; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. */ __le16 spi_tx_buf __aligned(IIO_DMA_MINALIGN); }; static int ad8460_hv_reset(struct ad8460_state *state) { int ret; ret = regmap_set_bits(state->regmap, AD8460_CTRL_REG(0x00), AD8460_HV_RESET_MSK); if (ret) return ret; fsleep(20); return regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x00), AD8460_HV_RESET_MSK); } static int ad8460_reset(const struct ad8460_state *state) { struct device *dev = &state->spi->dev; struct gpio_desc *reset; reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(reset)) return dev_err_probe(dev, PTR_ERR(reset), "Failed to get reset gpio"); if (reset) { /* minimum duration of 10ns */ ndelay(10); gpiod_set_value_cansleep(reset, 1); return 0; } /* bring all registers to their default state */ return regmap_write(state->regmap, AD8460_CTRL_REG(0x03), 1); } static int ad8460_enable_apg_mode(struct ad8460_state *state, int val) { int ret; ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02), AD8460_APG_MODE_ENABLE_MSK, FIELD_PREP(AD8460_APG_MODE_ENABLE_MSK, val)); if (ret) return ret; return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00), AD8460_WAVE_GEN_MODE_MSK, FIELD_PREP(AD8460_WAVE_GEN_MODE_MSK, val)); } static int ad8460_read_shutdown_flag(struct ad8460_state *state, u64 *flag) { int ret, val; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x0E), &val); if (ret) return ret; *flag = FIELD_GET(AD8460_SHUTDOWN_FLAG_MSK, val); return 0; } static int ad8460_get_hvdac_word(struct ad8460_state *state, int index, int *val) { int ret; ret = regmap_bulk_read(state->regmap, AD8460_HVDAC_DATA_WORD(index), &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH); if (ret) return ret; *val = le16_to_cpu(state->spi_tx_buf); return ret; } static int ad8460_set_hvdac_word(struct ad8460_state *state, int index, int val) { state->spi_tx_buf = cpu_to_le16(FIELD_PREP(AD8460_DATA_BYTE_FULL_MSK, val)); return regmap_bulk_write(state->regmap, AD8460_HVDAC_DATA_WORD(index), &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH); } static ssize_t ad8460_dac_input_read(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad8460_state *state = iio_priv(indio_dev); unsigned int reg; int ret; ret = ad8460_get_hvdac_word(state, private, ®); if (ret) return ret; return sysfs_emit(buf, "%u\n", reg); } static ssize_t ad8460_dac_input_write(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len) { struct ad8460_state *state = iio_priv(indio_dev); unsigned int reg; int ret; ret = kstrtou32(buf, 10, ®); if (ret) return ret; guard(mutex)(&state->lock); return ad8460_set_hvdac_word(state, private, reg); } static ssize_t ad8460_read_symbol(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad8460_state *state = iio_priv(indio_dev); unsigned int reg; int ret; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®); if (ret) return ret; return sysfs_emit(buf, "%lu\n", FIELD_GET(AD8460_PATTERN_DEPTH_MSK, reg)); } static ssize_t ad8460_write_symbol(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len) { struct ad8460_state *state = iio_priv(indio_dev); uint16_t sym; int ret; ret = kstrtou16(buf, 10, &sym); if (ret) return ret; guard(mutex)(&state->lock); return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02), AD8460_PATTERN_DEPTH_MSK, FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, sym)); } static ssize_t ad8460_read_toggle_en(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad8460_state *state = iio_priv(indio_dev); unsigned int reg; int ret; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®); if (ret) return ret; return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_APG_MODE_ENABLE_MSK, reg)); } static ssize_t ad8460_write_toggle_en(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len) { struct ad8460_state *state = iio_priv(indio_dev); bool toggle_en; int ret; ret = kstrtobool(buf, &toggle_en); if (ret) return ret; iio_device_claim_direct_scoped(return -EBUSY, indio_dev) return ad8460_enable_apg_mode(state, toggle_en); unreachable(); } static ssize_t ad8460_read_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad8460_state *state = iio_priv(indio_dev); unsigned int reg; int ret; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x01), ®); if (ret) return ret; return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_HVDAC_SLEEP_MSK, reg)); } static ssize_t ad8460_write_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len) { struct ad8460_state *state = iio_priv(indio_dev); bool pwr_down; u64 sdn_flag; int ret; ret = kstrtobool(buf, &pwr_down); if (ret) return ret; guard(mutex)(&state->lock); /* * If powerdown is set, HVDAC is enabled and the HV driver is * enabled via HV_RESET in case it is in shutdown mode, * If powerdown is cleared, HVDAC is set to shutdown state * as well as the HV driver. Quiescent current decreases and ouput is * floating (high impedance). */ ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x01), AD8460_HVDAC_SLEEP_MSK, FIELD_PREP(AD8460_HVDAC_SLEEP_MSK, pwr_down)); if (ret) return ret; if (!pwr_down) { ret = ad8460_read_shutdown_flag(state, &sdn_flag); if (ret) return ret; if (sdn_flag) { ret = ad8460_hv_reset(state); if (ret) return ret; } } ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00), AD8460_HV_SLEEP_MSK, FIELD_PREP(AD8460_HV_SLEEP_MSK, !pwr_down)); if (ret) return ret; return len; } static const char * const ad8460_powerdown_modes[] = { "three_state", }; static int ad8460_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { return 0; } static int ad8460_set_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int type) { return 0; } static int ad8460_set_sample(struct ad8460_state *state, int val) { int ret; ret = ad8460_enable_apg_mode(state, 1); if (ret) return ret; guard(mutex)(&state->lock); ret = ad8460_set_hvdac_word(state, 0, val); if (ret) return ret; return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02), AD8460_PATTERN_DEPTH_MSK, FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, 0)); } static int ad8460_set_fault_threshold(struct ad8460_state *state, enum ad8460_fault_type fault, unsigned int threshold) { return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault), AD8460_FAULT_LIMIT_MSK, FIELD_PREP(AD8460_FAULT_LIMIT_MSK, threshold)); } static int ad8460_get_fault_threshold(struct ad8460_state *state, enum ad8460_fault_type fault, unsigned int *threshold) { unsigned int val; int ret; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val); if (ret) return ret; *threshold = FIELD_GET(AD8460_FAULT_LIMIT_MSK, val); return ret; } static int ad8460_set_fault_threshold_en(struct ad8460_state *state, enum ad8460_fault_type fault, bool en) { return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault), AD8460_FAULT_ARM_MSK, FIELD_PREP(AD8460_FAULT_ARM_MSK, en)); } static int ad8460_get_fault_threshold_en(struct ad8460_state *state, enum ad8460_fault_type fault, bool *en) { unsigned int val; int ret; ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val); if (ret) return ret; *en = FIELD_GET(AD8460_FAULT_ARM_MSK, val); return 0; } static int ad8460_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct ad8460_state *state = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_VOLTAGE: iio_device_claim_direct_scoped(return -EBUSY, indio_dev) return ad8460_set_sample(state, val); unreachable(); case IIO_CURRENT: return regmap_write(state->regmap, AD8460_CTRL_REG(0x04), FIELD_PREP(AD8460_QUIESCENT_CURRENT_MSK, val)); default: return -EINVAL; } default: return -EINVAL; } } static int ad8460_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct ad8460_state *state = iio_priv(indio_dev); int data, ret; switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_VOLTAGE: scoped_guard(mutex, &state->lock) { ret = ad8460_get_hvdac_word(state, 0, &data); if (ret) return ret; } *val = data; return IIO_VAL_INT; case IIO_CURRENT: ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x04), &data); if (ret) return ret; *val = data; return IIO_VAL_INT; case IIO_TEMP: ret = iio_read_channel_raw(state->tmp_adc_channel, &data); if (ret) return ret; *val = data; return IIO_VAL_INT; default: return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: *val = clk_get_rate(state->sync_clk); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* * vCONV = vNOMINAL_SPAN * (DAC_CODE / 2**14) - 40V * vMAX = vNOMINAL_SPAN * (2**14 / 2**14) - 40V * vMIN = vNOMINAL_SPAN * (0 / 2**14) - 40V * vADJ = vCONV * (2000 / rSET) * (vREF / 1.2) * vSPAN = vADJ_MAX - vADJ_MIN * See datasheet page 49, section FULL-SCALE REDUCTION */ *val = AD8460_NOMINAL_VOLTAGE_SPAN * 2000 * state->refio_1p2v_mv; *val2 = state->ext_resistor_ohms * 1200; return IIO_VAL_FRACTIONAL; default: return -EINVAL; } } static int ad8460_select_fault_type(int chan_type, enum iio_event_direction dir) { switch (chan_type) { case IIO_VOLTAGE: switch (dir) { case IIO_EV_DIR_RISING: return AD8460_OVERVOLTAGE_POS; case IIO_EV_DIR_FALLING: return AD8460_OVERVOLTAGE_NEG; default: return -EINVAL; } case IIO_CURRENT: switch (dir) { case IIO_EV_DIR_RISING: return AD8460_OVERCURRENT_SRC; case IIO_EV_DIR_FALLING: return AD8460_OVERCURRENT_SNK; default: return -EINVAL; } case IIO_TEMP: switch (dir) { case IIO_EV_DIR_RISING: return AD8460_OVERTEMPERATURE; default: return -EINVAL; } default: return -EINVAL; } } static int ad8460_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int val, int val2) { struct ad8460_state *state = iio_priv(indio_dev); int fault; if (type != IIO_EV_TYPE_THRESH) return -EINVAL; if (info != IIO_EV_INFO_VALUE) return -EINVAL; fault = ad8460_select_fault_type(chan->type, dir); if (fault < 0) return fault; return ad8460_set_fault_threshold(state, fault, val); } static int ad8460_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int *val, int *val2) { struct ad8460_state *state = iio_priv(indio_dev); int fault; if (type != IIO_EV_TYPE_THRESH) return -EINVAL; if (info != IIO_EV_INFO_VALUE) return -EINVAL; fault = ad8460_select_fault_type(chan->type, dir); if (fault < 0) return fault; return ad8460_get_fault_threshold(state, fault, val); } static int ad8460_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, bool val) { struct ad8460_state *state = iio_priv(indio_dev); int fault; if (type != IIO_EV_TYPE_THRESH) return -EINVAL; fault = ad8460_select_fault_type(chan->type, dir); if (fault < 0) return fault; return ad8460_set_fault_threshold_en(state, fault, val); } static int ad8460_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir) { struct ad8460_state *state = iio_priv(indio_dev); int fault, ret; bool en; if (type != IIO_EV_TYPE_THRESH) return -EINVAL; fault = ad8460_select_fault_type(chan->type, dir); if (fault < 0) return fault; ret = ad8460_get_fault_threshold_en(state, fault, &en); if (ret) return ret; return en; } static int ad8460_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { struct ad8460_state *state = iio_priv(indio_dev); if (readval) return regmap_read(state->regmap, reg, readval); return regmap_write(state->regmap, reg, writeval); } static int ad8460_buffer_preenable(struct iio_dev *indio_dev) { struct ad8460_state *state = iio_priv(indio_dev); return ad8460_enable_apg_mode(state, 0); } static int ad8460_buffer_postdisable(struct iio_dev *indio_dev) { struct ad8460_state *state = iio_priv(indio_dev); return ad8460_enable_apg_mode(state, 1); } static const struct iio_buffer_setup_ops ad8460_buffer_setup_ops = { .preenable = &ad8460_buffer_preenable, .postdisable = &ad8460_buffer_postdisable, }; static const struct iio_info ad8460_info = { .read_raw = &ad8460_read_raw, .write_raw = &ad8460_write_raw, .write_event_value = &ad8460_write_event_value, .read_event_value = &ad8460_read_event_value, .write_event_config = &ad8460_write_event_config, .read_event_config = &ad8460_read_event_config, .debugfs_reg_access = &ad8460_reg_access, }; static const struct iio_enum ad8460_powerdown_mode_enum = { .items = ad8460_powerdown_modes, .num_items = ARRAY_SIZE(ad8460_powerdown_modes), .get = ad8460_get_powerdown_mode, .set = ad8460_set_powerdown_mode, }; #define AD8460_CHAN_EXT_INFO(_name, _what, _read, _write) { \ .name = (_name), \ .read = (_read), \ .write = (_write), \ .private = (_what), \ .shared = IIO_SEPARATE, \ } static const struct iio_chan_spec_ext_info ad8460_ext_info[] = { AD8460_CHAN_EXT_INFO("raw0", 0, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw1", 1, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw2", 2, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw3", 3, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw4", 4, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw5", 5, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw6", 6, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw7", 7, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw8", 8, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw9", 9, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw10", 10, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw11", 11, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw12", 12, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw13", 13, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw14", 14, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("raw15", 15, ad8460_dac_input_read, ad8460_dac_input_write), AD8460_CHAN_EXT_INFO("toggle_en", 0, ad8460_read_toggle_en, ad8460_write_toggle_en), AD8460_CHAN_EXT_INFO("symbol", 0, ad8460_read_symbol, ad8460_write_symbol), AD8460_CHAN_EXT_INFO("powerdown", 0, ad8460_read_powerdown, ad8460_write_powerdown), IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad8460_powerdown_mode_enum), IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad8460_powerdown_mode_enum), { } }; static const struct iio_event_spec ad8460_events[] = { { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_RISING, .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), }, { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_FALLING, .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), }, }; #define AD8460_VOLTAGE_CHAN { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ .output = 1, \ .indexed = 1, \ .channel = 0, \ .scan_index = 0, \ .scan_type = { \ .sign = 'u', \ .realbits = 14, \ .storagebits = 16, \ .endianness = IIO_CPU, \ }, \ .ext_info = ad8460_ext_info, \ .event_spec = ad8460_events, \ .num_event_specs = ARRAY_SIZE(ad8460_events), \ } #define AD8460_CURRENT_CHAN { \ .type = IIO_CURRENT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .output = 1, \ .indexed = 1, \ .channel = 0, \ .scan_index = -1, \ .event_spec = ad8460_events, \ .num_event_specs = ARRAY_SIZE(ad8460_events), \ } #define AD8460_TEMP_CHAN { \ .type = IIO_TEMP, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .indexed = 1, \ .channel = 0, \ .scan_index = -1, \ .event_spec = ad8460_events, \ .num_event_specs = 1, \ } static const struct iio_chan_spec ad8460_channels[] = { AD8460_VOLTAGE_CHAN, AD8460_CURRENT_CHAN, }; static const struct iio_chan_spec ad8460_channels_with_tmp_adc[] = { AD8460_VOLTAGE_CHAN, AD8460_CURRENT_CHAN, AD8460_TEMP_CHAN, }; static const struct regmap_config ad8460_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x7F, }; static const char * const ad8460_supplies[] = { "avdd_3p3v", "dvdd_3p3v", "vcc_5v", "hvcc", "hvee", "vref_5v" }; static int ad8460_probe(struct spi_device *spi) { struct device *dev = &spi->dev; struct ad8460_state *state; struct iio_dev *indio_dev; u32 tmp[2], temp; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); if (!indio_dev) return -ENOMEM; state = iio_priv(indio_dev); indio_dev->name = "ad8460"; indio_dev->info = &ad8460_info; state->spi = spi; state->regmap = devm_regmap_init_spi(spi, &ad8460_regmap_config); if (IS_ERR(state->regmap)) return dev_err_probe(dev, PTR_ERR(state->regmap), "Failed to initialize regmap"); ret = devm_mutex_init(dev, &state->lock); if (ret) return ret; state->sync_clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(state->sync_clk)) return dev_err_probe(dev, PTR_ERR(state->sync_clk), "Failed to get sync clk\n"); state->tmp_adc_channel = devm_iio_channel_get(dev, "ad8460-tmp"); if (IS_ERR(state->tmp_adc_channel)) { if (PTR_ERR(state->tmp_adc_channel) == -EPROBE_DEFER) return -EPROBE_DEFER; indio_dev->channels = ad8460_channels; indio_dev->num_channels = ARRAY_SIZE(ad8460_channels); } else { indio_dev->channels = ad8460_channels_with_tmp_adc; indio_dev->num_channels = ARRAY_SIZE(ad8460_channels_with_tmp_adc); } ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad8460_supplies), ad8460_supplies); if (ret) return dev_err_probe(dev, ret, "Failed to enable power supplies\n"); ret = devm_regulator_get_enable_read_voltage(dev, "refio_1p2v"); if (ret < 0 && ret != -ENODEV) return dev_err_probe(dev, ret, "Failed to get reference voltage\n"); state->refio_1p2v_mv = ret == -ENODEV ? 1200 : ret / 1000; if (!in_range(state->refio_1p2v_mv, AD8460_MIN_VREFIO_UV / 1000, AD8460_MAX_VREFIO_UV / 1000)) return dev_err_probe(dev, -EINVAL, "Invalid ref voltage range(%u mV) [%u mV, %u mV]\n", state->refio_1p2v_mv, AD8460_MIN_VREFIO_UV / 1000, AD8460_MAX_VREFIO_UV / 1000); ret = device_property_read_u32(dev, "adi,external-resistor-ohms", &state->ext_resistor_ohms); if (ret) state->ext_resistor_ohms = 2000; else if (!in_range(state->ext_resistor_ohms, AD8460_MIN_EXT_RESISTOR_OHMS, AD8460_MAX_EXT_RESISTOR_OHMS)) return dev_err_probe(dev, -EINVAL, "Invalid resistor set range(%u) [%u, %u]\n", state->ext_resistor_ohms, AD8460_MIN_EXT_RESISTOR_OHMS, AD8460_MAX_EXT_RESISTOR_OHMS); ret = device_property_read_u32_array(dev, "adi,range-microamp", tmp, ARRAY_SIZE(tmp)); if (!ret) { if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERCURRENT_UA)) regmap_write(state->regmap, AD8460_CTRL_REG(0x08), FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | AD8460_CURRENT_LIMIT_CONV(tmp[1])); if (in_range(tmp[0], -AD8460_ABS_MAX_OVERCURRENT_UA, 0)) regmap_write(state->regmap, AD8460_CTRL_REG(0x09), FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | AD8460_CURRENT_LIMIT_CONV(abs(tmp[0]))); } ret = device_property_read_u32_array(dev, "adi,range-microvolt", tmp, ARRAY_SIZE(tmp)); if (!ret) { if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERVOLTAGE_UV)) regmap_write(state->regmap, AD8460_CTRL_REG(0x0A), FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | AD8460_VOLTAGE_LIMIT_CONV(tmp[1])); if (in_range(tmp[0], -AD8460_ABS_MAX_OVERVOLTAGE_UV, 0)) regmap_write(state->regmap, AD8460_CTRL_REG(0x0B), FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | AD8460_VOLTAGE_LIMIT_CONV(abs(tmp[0]))); } ret = device_property_read_u32(dev, "adi,max-millicelsius", &temp); if (!ret) { if (in_range(temp, AD8460_MIN_OVERTEMPERATURE_MC, AD8460_MAX_OVERTEMPERATURE_MC)) regmap_write(state->regmap, AD8460_CTRL_REG(0x0C), FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | AD8460_TEMP_LIMIT_CONV(abs(temp))); } ret = ad8460_reset(state); if (ret) return ret; /* Enables DAC by default */ ret = regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x01), AD8460_HVDAC_SLEEP_MSK); if (ret) return ret; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->setup_ops = &ad8460_buffer_setup_ops; ret = devm_iio_dmaengine_buffer_setup_ext(dev, indio_dev, "tx", IIO_BUFFER_DIRECTION_OUT); if (ret) return dev_err_probe(dev, ret, "Failed to get DMA buffer\n"); return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad8460_of_match[] = { { .compatible = "adi,ad8460" }, { } }; MODULE_DEVICE_TABLE(of, ad8460_of_match); static const struct spi_device_id ad8460_spi_match[] = { { .name = "ad8460" }, { } }; MODULE_DEVICE_TABLE(spi, ad8460_spi_match); static struct spi_driver ad8460_driver = { .driver = { .name = "ad8460", .of_match_table = ad8460_of_match, }, .probe = ad8460_probe, .id_table = ad8460_spi_match, }; module_spi_driver(ad8460_driver); MODULE_AUTHOR("Mariel Tinaco