/* * AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver * * Copyright 2012 Analog Devices Inc. * * Licensed under the GPL-2. */ #include <linux/device.h> #include <linux/err.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/platform_data/ad5755.h> #define AD5755_NUM_CHANNELS 4 #define AD5755_ADDR(x) ((x) << 16) #define AD5755_WRITE_REG_DATA(chan) (chan) #define AD5755_WRITE_REG_GAIN(chan) (0x08 | (chan)) #define AD5755_WRITE_REG_OFFSET(chan) (0x10 | (chan)) #define AD5755_WRITE_REG_CTRL(chan) (0x1c | (chan)) #define AD5755_READ_REG_DATA(chan) (chan) #define AD5755_READ_REG_CTRL(chan) (0x4 | (chan)) #define AD5755_READ_REG_GAIN(chan) (0x8 | (chan)) #define AD5755_READ_REG_OFFSET(chan) (0xc | (chan)) #define AD5755_READ_REG_CLEAR(chan) (0x10 | (chan)) #define AD5755_READ_REG_SLEW(chan) (0x14 | (chan)) #define AD5755_READ_REG_STATUS 0x18 #define AD5755_READ_REG_MAIN 0x19 #define AD5755_READ_REG_DC_DC 0x1a #define AD5755_CTRL_REG_SLEW 0x0 #define AD5755_CTRL_REG_MAIN 0x1 #define AD5755_CTRL_REG_DAC 0x2 #define AD5755_CTRL_REG_DC_DC 0x3 #define AD5755_CTRL_REG_SW 0x4 #define AD5755_READ_FLAG 0x800000 #define AD5755_NOOP 0x1CE000 #define AD5755_DAC_INT_EN BIT(8) #define AD5755_DAC_CLR_EN BIT(7) #define AD5755_DAC_OUT_EN BIT(6) #define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR BIT(5) #define AD5755_DAC_DC_DC_EN BIT(4) #define AD5755_DAC_VOLTAGE_OVERRANGE_EN BIT(3) #define AD5755_DC_DC_MAXV 0 #define AD5755_DC_DC_FREQ_SHIFT 2 #define AD5755_DC_DC_PHASE_SHIFT 4 #define AD5755_EXT_DC_DC_COMP_RES BIT(6) #define AD5755_SLEW_STEP_SIZE_SHIFT 0 #define AD5755_SLEW_RATE_SHIFT 3 #define AD5755_SLEW_ENABLE BIT(12) /** * struct ad5755_chip_info - chip specific information * @channel_template: channel specification * @calib_shift: shift for the calibration data registers * @has_voltage_out: whether the chip has voltage outputs */ struct ad5755_chip_info { const struct iio_chan_spec channel_template; unsigned int calib_shift; bool has_voltage_out; }; /** * struct ad5755_state - driver instance specific data * @spi: spi device the driver is attached to * @chip_info: chip model specific constants, available modes etc * @pwr_down: bitmask which contains hether a channel is powered down or not * @ctrl: software shadow of the channel ctrl registers * @channels: iio channel spec for the device * @data: spi transfer buffers */ struct ad5755_state { struct spi_device *spi; const struct ad5755_chip_info *chip_info; unsigned int pwr_down; unsigned int ctrl[AD5755_NUM_CHANNELS]; struct iio_chan_spec channels[AD5755_NUM_CHANNELS]; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. */ union { __be32 d32; u8 d8[4]; } data[2] ____cacheline_aligned; }; enum ad5755_type { ID_AD5755, ID_AD5757, ID_AD5735, ID_AD5737, }; static int ad5755_write_unlocked(struct iio_dev *indio_dev, unsigned int reg, unsigned int val) { struct ad5755_state *st = iio_priv(indio_dev); st->data[0].d32 = cpu_to_be32((reg << 16) | val); return spi_write(st->spi, &st->data[0].d8[1], 3); } static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev, unsigned int channel, unsigned int reg, unsigned int val) { return ad5755_write_unlocked(indio_dev, AD5755_WRITE_REG_CTRL(channel), (reg << 13) | val); } static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg, unsigned int val) { int ret; mutex_lock(&indio_dev->mlock); ret = ad5755_write_unlocked(indio_dev, reg, val); mutex_unlock(&indio_dev->mlock); return ret; } static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel, unsigned int reg, unsigned int val) { int ret; mutex_lock(&indio_dev->mlock); ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val); mutex_unlock(&indio_dev->mlock); return ret; } static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) { struct ad5755_state *st = iio_priv(indio_dev); int ret; struct spi_transfer t[] = { { .tx_buf = &st->data[0].d8[1], .len = 3, .cs_change = 1, }, { .tx_buf = &st->data[1].d8[1], .rx_buf = &st->data[1].d8[1], .len = 3, }, }; mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16)); st->data[1].d32 = cpu_to_be32(AD5755_NOOP); ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; mutex_unlock(&indio_dev->mlock); return ret; } static int ad5755_update_dac_ctrl(struct iio_dev *indio_dev, unsigned int channel, unsigned int set, unsigned int clr) { struct ad5755_state *st = iio_priv(indio_dev); int ret; st->ctrl[channel] |= set; st->ctrl[channel] &= ~clr; ret = ad5755_write_ctrl_unlocked(indio_dev, channel, AD5755_CTRL_REG_DAC, st->ctrl[channel]); return ret; } static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev, unsigned int channel, bool pwr_down) { struct ad5755_state *st = iio_priv(indio_dev); unsigned int mask = BIT(channel); mutex_lock(&indio_dev->mlock); if ((bool)(st->pwr_down & mask) == pwr_down) goto out_unlock; if (!pwr_down) { st->pwr_down &= ~mask; ad5755_update_dac_ctrl(indio_dev, channel, AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN, 0); udelay(200); ad5755_update_dac_ctrl(indio_dev, channel, AD5755_DAC_OUT_EN, 0); } else { st->pwr_down |= mask; ad5755_update_dac_ctrl(indio_dev, channel, 0, AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN | AD5755_DAC_DC_DC_EN); } out_unlock: mutex_unlock(&indio_dev->mlock); return 0; } static const int ad5755_min_max_table[][2] = { [AD5755_MODE_VOLTAGE_0V_5V] = { 0, 5000 }, [AD5755_MODE_VOLTAGE_0V_10V] = { 0, 10000 }, [AD5755_MODE_VOLTAGE_PLUSMINUS_5V] = { -5000, 5000 }, [AD5755_MODE_VOLTAGE_PLUSMINUS_10V] = { -10000, 10000 }, [AD5755_MODE_CURRENT_4mA_20mA] = { 4, 20 }, [AD5755_MODE_CURRENT_0mA_20mA] = { 0, 20 }, [AD5755_MODE_CURRENT_0mA_24mA] = { 0, 24 }, }; static void ad5755_get_min_max(struct ad5755_state *st, struct iio_chan_spec const *chan, int *min, int *max) { enum ad5755_mode mode = st->ctrl[chan->channel] & 7; *min = ad5755_min_max_table[mode][0]; *max = ad5755_min_max_table[mode][1]; } static inline int ad5755_get_offset(struct ad5755_state *st, struct iio_chan_spec const *chan) { int min, max; ad5755_get_min_max(st, chan, &min, &max); return (min * (1 << chan->scan_type.realbits)) / (max - min); } static int ad5755_chan_reg_info(struct ad5755_state *st, struct iio_chan_spec const *chan, long info, bool write, unsigned int *reg, unsigned int *shift, unsigned int *offset) { switch (info) { case IIO_CHAN_INFO_RAW: if (write) *reg = AD5755_WRITE_REG_DATA(chan->address); else *reg = AD5755_READ_REG_DATA(chan->address); *shift = chan->scan_type.shift; *offset = 0; break; case IIO_CHAN_INFO_CALIBBIAS: if (write) *reg = AD5755_WRITE_REG_OFFSET(chan->address); else *reg = AD5755_READ_REG_OFFSET(chan->address); *shift = st->chip_info->calib_shift; *offset = 32768; break; case IIO_CHAN_INFO_CALIBSCALE: if (write) *reg = AD5755_WRITE_REG_GAIN(chan->address); else *reg = AD5755_READ_REG_GAIN(chan->address); *shift = st->chip_info->calib_shift; *offset = 0; break; default: return -EINVAL; } return 0; } static int ad5755_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { struct ad5755_state *st = iio_priv(indio_dev); unsigned int reg, shift, offset; int min, max; int ret; switch (info) { case IIO_CHAN_INFO_SCALE: ad5755_get_min_max(st, chan, &min, &max); *val = max - min; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: *val = ad5755_get_offset(st, chan); return IIO_VAL_INT; default: ret = ad5755_chan_reg_info(st, chan, info, false, ®, &shift, &offset); if (ret) return ret; ret = ad5755_read(indio_dev, reg); if (ret < 0) return ret; *val = (ret - offset) >> shift; return IIO_VAL_INT; } return -EINVAL; } static int ad5755_write_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int val, int val2, long info) { struct ad5755_state *st = iio_priv(indio_dev); unsigned int shift, reg, offset; int ret; ret = ad5755_chan_reg_info(st, chan, info, true, ®, &shift, &offset); if (ret) return ret; val <<= shift; val += offset; if (val < 0 || val > 0xffff) return -EINVAL; return ad5755_write(indio_dev, reg, val); } static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv, const struct iio_chan_spec *chan, char *buf) { struct ad5755_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", (bool)(st->pwr_down & (1 << chan->channel))); } static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv, struct iio_chan_spec const *chan, const char *buf, size_t len) { bool pwr_down; int ret; ret = strtobool(buf, &pwr_down); if (ret) return ret; ret = ad5755_set_channel_pwr_down(indio_dev, chan->channel, pwr_down); return ret ? ret : len; } static const struct iio_info ad5755_info = { .read_raw = ad5755_read_raw, .write_raw = ad5755_write_raw, .driver_module = THIS_MODULE, }; static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { { .name = "powerdown", .read = ad5755_read_powerdown, .write = ad5755_write_powerdown, .shared = IIO_SEPARATE, }, { }, }; #define AD5755_CHANNEL(_bits) { \ .indexed = 1, \ .output = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_OFFSET) | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .scan_type = { \ .sign = 'u', \ .realbits = (_bits), \ .storagebits = 16, \ .shift = 16 - (_bits), \ }, \ .ext_info = ad5755_ext_info, \ } static const struct ad5755_chip_info ad5755_chip_info_tbl[] = { [ID_AD5735] = { .channel_template = AD5755_CHANNEL(14), .has_voltage_out = true, .calib_shift = 4, }, [ID_AD5737] = { .channel_template = AD5755_CHANNEL(14), .has_voltage_out = false, .calib_shift = 4, }, [ID_AD5755] = { .channel_template = AD5755_CHANNEL(16), .has_voltage_out = true, .calib_shift = 0, }, [ID_AD5757] = { .channel_template = AD5755_CHANNEL(16), .has_voltage_out = false, .calib_shift = 0, }, }; static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode) { switch (mode) { case AD5755_MODE_VOLTAGE_0V_5V: case AD5755_MODE_VOLTAGE_0V_10V: case AD5755_MODE_VOLTAGE_PLUSMINUS_5V: case AD5755_MODE_VOLTAGE_PLUSMINUS_10V: return st->chip_info->has_voltage_out; case AD5755_MODE_CURRENT_4mA_20mA: case AD5755_MODE_CURRENT_0mA_20mA: case AD5755_MODE_CURRENT_0mA_24mA: return true; default: return false; } } static int ad5755_setup_pdata(struct iio_dev *indio_dev, const struct ad5755_platform_data *pdata) { struct ad5755_state *st = iio_priv(indio_dev); unsigned int val; unsigned int i; int ret; if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE || pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ || pdata->dc_dc_maxv > AD5755_DC_DC_MAXV_29V5) return -EINVAL; val = pdata->dc_dc_maxv << AD5755_DC_DC_MAXV; val |= pdata->dc_dc_freq << AD5755_DC_DC_FREQ_SHIFT; val |= pdata->dc_dc_phase << AD5755_DC_DC_PHASE_SHIFT; if (pdata->ext_dc_dc_compenstation_resistor) val |= AD5755_EXT_DC_DC_COMP_RES; ret = ad5755_write_ctrl(indio_dev, 0, AD5755_CTRL_REG_DC_DC, val); if (ret < 0) return ret; for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) { val = pdata->dac[i].slew.step_size << AD5755_SLEW_STEP_SIZE_SHIFT; val |= pdata->dac[i].slew.rate << AD5755_SLEW_RATE_SHIFT; if (pdata->dac[i].slew.enable) val |= AD5755_SLEW_ENABLE; ret = ad5755_write_ctrl(indio_dev, i, AD5755_CTRL_REG_SLEW, val); if (ret < 0) return ret; } for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) { if (!ad5755_is_valid_mode(st, pdata->dac[i].mode)) return -EINVAL; val = 0; if (!pdata->dac[i].ext_current_sense_resistor) val |= AD5755_DAC_INT_CURRENT_SENSE_RESISTOR; if (pdata->dac[i].enable_voltage_overrange) val |= AD5755_DAC_VOLTAGE_OVERRANGE_EN; val |= pdata->dac[i].mode; ret = ad5755_update_dac_ctrl(indio_dev, i, val, 0); if (ret < 0) return ret; } return 0; } static bool ad5755_is_voltage_mode(enum ad5755_mode mode) { switch (mode) { case AD5755_MODE_VOLTAGE_0V_5V: case AD5755_MODE_VOLTAGE_0V_10V: case AD5755_MODE_VOLTAGE_PLUSMINUS_5V: case AD5755_MODE_VOLTAGE_PLUSMINUS_10V: return true; default: return false; } } static int ad5755_init_channels(struct iio_dev *indio_dev, const struct ad5755_platform_data *pdata) { struct ad5755_state *st = iio_priv(indio_dev); struct iio_chan_spec *channels = st->channels; unsigned int i; for (i = 0; i < AD5755_NUM_CHANNELS; ++i) { channels[i] = st->chip_info->channel_template; channels[i].channel = i; channels[i].address = i; if (pdata && ad5755_is_voltage_mode(pdata->dac[i].mode)) channels[i].type = IIO_VOLTAGE; else channels[i].type = IIO_CURRENT; } indio_dev->channels = channels; return 0; } #define AD5755_DEFAULT_DAC_PDATA { \ .mode = AD5755_MODE_CURRENT_4mA_20mA, \ .ext_current_sense_resistor = true, \ .enable_voltage_overrange = false, \ .slew = { \ .enable = false, \ .rate = AD5755_SLEW_RATE_64k, \ .step_size = AD5755_SLEW_STEP_SIZE_1, \ }, \ } static const struct ad5755_platform_data ad5755_default_pdata = { .ext_dc_dc_compenstation_resistor = false, .dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE, .dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ, .dc_dc_maxv = AD5755_DC_DC_MAXV_23V, .dac = { [0] = AD5755_DEFAULT_DAC_PDATA, [1] = AD5755_DEFAULT_DAC_PDATA, [2] = AD5755_DEFAULT_DAC_PDATA, [3] = AD5755_DEFAULT_DAC_PDATA, }, }; static int ad5755_probe(struct spi_device *spi) { enum ad5755_type type = spi_get_device_id(spi)->driver_data; const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad5755_state *st; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; } st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); st->chip_info = &ad5755_chip_info_tbl[type]; st->spi = spi; st->pwr_down = 0xf; indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5755_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->num_channels = AD5755_NUM_CHANNELS; if (!pdata) pdata = &ad5755_default_pdata; ret = ad5755_init_channels(indio_dev, pdata); if (ret) return ret; ret = ad5755_setup_pdata(indio_dev, pdata); if (ret) return ret; return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad5755_id[] = { { "ad5755", ID_AD5755 }, { "ad5755-1", ID_AD5755 }, { "ad5757", ID_AD5757 }, { "ad5735", ID_AD5735 }, { "ad5737", ID_AD5737 }, {} }; MODULE_DEVICE_TABLE(spi, ad5755_id); static struct spi_driver ad5755_driver = { .driver = { .name = "ad5755", .owner = THIS_MODULE, }, .probe = ad5755_probe, .id_table = ad5755_id, }; module_spi_driver(ad5755_driver); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("Analog Devices AD5755/55-1/57/35/37 DAC"); MODULE_LICENSE("GPL v2");