| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * AD8460 Waveform generator DAC Driver
- *
- * Copyright (C) 2024 Analog Devices, Inc.
- */
- #include <linux/bitfield.h>
- #include <linux/cleanup.h>
- #include <linux/clk.h>
- #include <linux/debugfs.h>
- #include <linux/delay.h>
- #include <linux/dmaengine.h>
- #include <linux/gpio/consumer.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/mod_devicetable.h>
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
- #include <linux/spi/spi.h>
- #include <linux/iio/buffer.h>
- #include <linux/iio/buffer-dma.h>
- #include <linux/iio/buffer-dmaengine.h>
- #include <linux/iio/consumer.h>
- #include <linux/iio/events.h>
- #include <linux/iio/iio.h>
- #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;
- if (!iio_device_claim_direct(indio_dev))
- return -EBUSY;
- ret = ad8460_enable_apg_mode(state, toggle_en);
- iio_device_release_direct(indio_dev);
- return ret;
- }
- 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);
- int ret;
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- switch (chan->type) {
- case IIO_VOLTAGE:
- if (!iio_device_claim_direct(indio_dev))
- return -EBUSY;
- ret = ad8460_set_sample(state, val);
- iio_device_release_direct(indio_dev);
- return ret;
- 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 <mariel.tinaco@analog.com");
- MODULE_DESCRIPTION("AD8460 DAC driver");
- MODULE_LICENSE("GPL");
- MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
|