|  | // SPDX-License-Identifier: GPL-2.0-only | 
|  | /* | 
|  | * AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver | 
|  | * | 
|  | * Copyright 2012 Analog Devices Inc. | 
|  | */ | 
|  |  | 
|  | #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/property.h> | 
|  |  | 
|  | #include <linux/iio/iio.h> | 
|  | #include <linux/iio/sysfs.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) | 
|  |  | 
|  | enum ad5755_mode { | 
|  | AD5755_MODE_VOLTAGE_0V_5V		= 0, | 
|  | AD5755_MODE_VOLTAGE_0V_10V		= 1, | 
|  | AD5755_MODE_VOLTAGE_PLUSMINUS_5V	= 2, | 
|  | AD5755_MODE_VOLTAGE_PLUSMINUS_10V	= 3, | 
|  | AD5755_MODE_CURRENT_4mA_20mA		= 4, | 
|  | AD5755_MODE_CURRENT_0mA_20mA		= 5, | 
|  | AD5755_MODE_CURRENT_0mA_24mA		= 6, | 
|  | }; | 
|  |  | 
|  | enum ad5755_dc_dc_phase { | 
|  | AD5755_DC_DC_PHASE_ALL_SAME_EDGE		= 0, | 
|  | AD5755_DC_DC_PHASE_A_B_SAME_EDGE_C_D_OPP_EDGE	= 1, | 
|  | AD5755_DC_DC_PHASE_A_C_SAME_EDGE_B_D_OPP_EDGE	= 2, | 
|  | AD5755_DC_DC_PHASE_90_DEGREE			= 3, | 
|  | }; | 
|  |  | 
|  | enum ad5755_dc_dc_freq { | 
|  | AD5755_DC_DC_FREQ_250kHZ = 0, | 
|  | AD5755_DC_DC_FREQ_410kHZ = 1, | 
|  | AD5755_DC_DC_FREQ_650kHZ = 2, | 
|  | }; | 
|  |  | 
|  | enum ad5755_dc_dc_maxv { | 
|  | AD5755_DC_DC_MAXV_23V	= 0, | 
|  | AD5755_DC_DC_MAXV_24V5	= 1, | 
|  | AD5755_DC_DC_MAXV_27V	= 2, | 
|  | AD5755_DC_DC_MAXV_29V5	= 3, | 
|  | }; | 
|  |  | 
|  | enum ad5755_slew_rate { | 
|  | AD5755_SLEW_RATE_64k	= 0, | 
|  | AD5755_SLEW_RATE_32k	= 1, | 
|  | AD5755_SLEW_RATE_16k	= 2, | 
|  | AD5755_SLEW_RATE_8k	= 3, | 
|  | AD5755_SLEW_RATE_4k	= 4, | 
|  | AD5755_SLEW_RATE_2k	= 5, | 
|  | AD5755_SLEW_RATE_1k	= 6, | 
|  | AD5755_SLEW_RATE_500	= 7, | 
|  | AD5755_SLEW_RATE_250	= 8, | 
|  | AD5755_SLEW_RATE_125	= 9, | 
|  | AD5755_SLEW_RATE_64	= 10, | 
|  | AD5755_SLEW_RATE_32	= 11, | 
|  | AD5755_SLEW_RATE_16	= 12, | 
|  | AD5755_SLEW_RATE_8	= 13, | 
|  | AD5755_SLEW_RATE_4	= 14, | 
|  | AD5755_SLEW_RATE_0_5	= 15, | 
|  | }; | 
|  |  | 
|  | enum ad5755_slew_step_size { | 
|  | AD5755_SLEW_STEP_SIZE_1 = 0, | 
|  | AD5755_SLEW_STEP_SIZE_2 = 1, | 
|  | AD5755_SLEW_STEP_SIZE_4 = 2, | 
|  | AD5755_SLEW_STEP_SIZE_8 = 3, | 
|  | AD5755_SLEW_STEP_SIZE_16 = 4, | 
|  | AD5755_SLEW_STEP_SIZE_32 = 5, | 
|  | AD5755_SLEW_STEP_SIZE_64 = 6, | 
|  | AD5755_SLEW_STEP_SIZE_128 = 7, | 
|  | AD5755_SLEW_STEP_SIZE_256 = 8, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * struct ad5755_platform_data - AD5755 DAC driver platform data | 
|  | * @ext_dc_dc_compenstation_resistor: Whether an external DC-DC converter | 
|  | * compensation register is used. | 
|  | * @dc_dc_phase: DC-DC converter phase. | 
|  | * @dc_dc_freq: DC-DC converter frequency. | 
|  | * @dc_dc_maxv: DC-DC maximum allowed boost voltage. | 
|  | * @dac: Per DAC instance parameters. | 
|  | * @dac.mode: The mode to be used for the DAC output. | 
|  | * @dac.ext_current_sense_resistor: Whether an external current sense resistor | 
|  | * is used. | 
|  | * @dac.enable_voltage_overrange: Whether to enable 20% voltage output overrange. | 
|  | * @dac.slew.enable: Whether to enable digital slew. | 
|  | * @dac.slew.rate: Slew rate of the digital slew. | 
|  | * @dac.slew.step_size: Slew step size of the digital slew. | 
|  | **/ | 
|  | struct ad5755_platform_data { | 
|  | bool ext_dc_dc_compenstation_resistor; | 
|  | enum ad5755_dc_dc_phase dc_dc_phase; | 
|  | enum ad5755_dc_dc_freq dc_dc_freq; | 
|  | enum ad5755_dc_dc_maxv dc_dc_maxv; | 
|  |  | 
|  | struct { | 
|  | enum ad5755_mode mode; | 
|  | bool ext_current_sense_resistor; | 
|  | bool enable_voltage_overrange; | 
|  | struct { | 
|  | bool enable; | 
|  | enum ad5755_slew_rate rate; | 
|  | enum ad5755_slew_step_size step_size; | 
|  | } slew; | 
|  | } dac[4]; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * 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 | 
|  | * @lock:	lock to protect the data buffer during SPI ops | 
|  | * @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]; | 
|  | struct mutex			lock; | 
|  |  | 
|  | /* | 
|  | * DMA (thus cache coherency maintenance) may require the | 
|  | * transfer buffers to live in their own cache lines. | 
|  | */ | 
|  |  | 
|  | union { | 
|  | __be32 d32; | 
|  | u8 d8[4]; | 
|  | } data[2] __aligned(IIO_DMA_MINALIGN); | 
|  | }; | 
|  |  | 
|  | enum ad5755_type { | 
|  | ID_AD5755, | 
|  | ID_AD5757, | 
|  | ID_AD5735, | 
|  | ID_AD5737, | 
|  | }; | 
|  |  | 
|  | static const int ad5755_dcdc_freq_table[][2] = { | 
|  | { 250000, AD5755_DC_DC_FREQ_250kHZ }, | 
|  | { 410000, AD5755_DC_DC_FREQ_410kHZ }, | 
|  | { 650000, AD5755_DC_DC_FREQ_650kHZ } | 
|  | }; | 
|  |  | 
|  | static const int ad5755_dcdc_maxv_table[][2] = { | 
|  | { 23000000, AD5755_DC_DC_MAXV_23V }, | 
|  | { 24500000, AD5755_DC_DC_MAXV_24V5 }, | 
|  | { 27000000, AD5755_DC_DC_MAXV_27V }, | 
|  | { 29500000, AD5755_DC_DC_MAXV_29V5 }, | 
|  | }; | 
|  |  | 
|  | static const int ad5755_slew_rate_table[][2] = { | 
|  | { 64000, AD5755_SLEW_RATE_64k }, | 
|  | { 32000, AD5755_SLEW_RATE_32k }, | 
|  | { 16000, AD5755_SLEW_RATE_16k }, | 
|  | { 8000, AD5755_SLEW_RATE_8k }, | 
|  | { 4000, AD5755_SLEW_RATE_4k }, | 
|  | { 2000, AD5755_SLEW_RATE_2k }, | 
|  | { 1000, AD5755_SLEW_RATE_1k }, | 
|  | { 500, AD5755_SLEW_RATE_500 }, | 
|  | { 250, AD5755_SLEW_RATE_250 }, | 
|  | { 125, AD5755_SLEW_RATE_125 }, | 
|  | { 64, AD5755_SLEW_RATE_64 }, | 
|  | { 32, AD5755_SLEW_RATE_32 }, | 
|  | { 16, AD5755_SLEW_RATE_16 }, | 
|  | { 8, AD5755_SLEW_RATE_8 }, | 
|  | { 4, AD5755_SLEW_RATE_4 }, | 
|  | { 0, AD5755_SLEW_RATE_0_5 }, | 
|  | }; | 
|  |  | 
|  | static const int ad5755_slew_step_table[][2] = { | 
|  | { 256, AD5755_SLEW_STEP_SIZE_256 }, | 
|  | { 128, AD5755_SLEW_STEP_SIZE_128 }, | 
|  | { 64, AD5755_SLEW_STEP_SIZE_64 }, | 
|  | { 32, AD5755_SLEW_STEP_SIZE_32 }, | 
|  | { 16, AD5755_SLEW_STEP_SIZE_16 }, | 
|  | { 4, AD5755_SLEW_STEP_SIZE_4 }, | 
|  | { 2, AD5755_SLEW_STEP_SIZE_2 }, | 
|  | { 1, AD5755_SLEW_STEP_SIZE_1 }, | 
|  | }; | 
|  |  | 
|  | 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) | 
|  | { | 
|  | struct ad5755_state *st = iio_priv(indio_dev); | 
|  | int ret; | 
|  |  | 
|  | mutex_lock(&st->lock); | 
|  | ret = ad5755_write_unlocked(indio_dev, reg, val); | 
|  | mutex_unlock(&st->lock); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel, | 
|  | unsigned int reg, unsigned int val) | 
|  | { | 
|  | struct ad5755_state *st = iio_priv(indio_dev); | 
|  | int ret; | 
|  |  | 
|  | mutex_lock(&st->lock); | 
|  | ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val); | 
|  | mutex_unlock(&st->lock); | 
|  |  | 
|  | 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(&st->lock); | 
|  |  | 
|  | 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(&st->lock); | 
|  |  | 
|  | 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(&st->lock); | 
|  |  | 
|  | 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(&st->lock); | 
|  |  | 
|  | 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 sysfs_emit(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 = kstrtobool(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, | 
|  | }; | 
|  |  | 
|  | 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 struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) | 
|  | { | 
|  | struct fwnode_handle *pp; | 
|  | struct ad5755_platform_data *pdata; | 
|  | unsigned int tmp; | 
|  | unsigned int tmparray[3]; | 
|  | int devnr, i; | 
|  |  | 
|  | if (!dev_fwnode(dev)) | 
|  | return NULL; | 
|  |  | 
|  | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 
|  | if (!pdata) | 
|  | return NULL; | 
|  |  | 
|  | pdata->ext_dc_dc_compenstation_resistor = | 
|  | device_property_read_bool(dev, "adi,ext-dc-dc-compenstation-resistor"); | 
|  |  | 
|  | pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE; | 
|  | device_property_read_u32(dev, "adi,dc-dc-phase", &pdata->dc_dc_phase); | 
|  |  | 
|  | pdata->dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ; | 
|  | if (!device_property_read_u32(dev, "adi,dc-dc-freq-hz", &tmp)) { | 
|  | for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_freq_table); i++) { | 
|  | if (tmp == ad5755_dcdc_freq_table[i][0]) { | 
|  | pdata->dc_dc_freq = ad5755_dcdc_freq_table[i][1]; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) | 
|  | dev_err(dev, | 
|  | "adi,dc-dc-freq out of range selecting 410kHz\n"); | 
|  | } | 
|  |  | 
|  | pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V; | 
|  | if (!device_property_read_u32(dev, "adi,dc-dc-max-microvolt", &tmp)) { | 
|  | for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_maxv_table); i++) { | 
|  | if (tmp == ad5755_dcdc_maxv_table[i][0]) { | 
|  | pdata->dc_dc_maxv = ad5755_dcdc_maxv_table[i][1]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) | 
|  | dev_err(dev, | 
|  | "adi,dc-dc-maxv out of range selecting 23V\n"); | 
|  | } | 
|  |  | 
|  | devnr = 0; | 
|  | device_for_each_child_node(dev, pp) { | 
|  | if (devnr >= AD5755_NUM_CHANNELS) { | 
|  | dev_err(dev, | 
|  | "There are too many channels defined in DT\n"); | 
|  | goto error_out; | 
|  | } | 
|  |  | 
|  | pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA; | 
|  | fwnode_property_read_u32(pp, "adi,mode", &pdata->dac[devnr].mode); | 
|  |  | 
|  | pdata->dac[devnr].ext_current_sense_resistor = | 
|  | fwnode_property_read_bool(pp, "adi,ext-current-sense-resistor"); | 
|  |  | 
|  | pdata->dac[devnr].enable_voltage_overrange = | 
|  | fwnode_property_read_bool(pp, "adi,enable-voltage-overrange"); | 
|  |  | 
|  | if (!fwnode_property_read_u32_array(pp, "adi,slew", tmparray, 3)) { | 
|  | pdata->dac[devnr].slew.enable = tmparray[0]; | 
|  |  | 
|  | pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; | 
|  | for (i = 0; i < ARRAY_SIZE(ad5755_slew_rate_table); i++) { | 
|  | if (tmparray[1] == ad5755_slew_rate_table[i][0]) { | 
|  | pdata->dac[devnr].slew.rate = | 
|  | ad5755_slew_rate_table[i][1]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (i == ARRAY_SIZE(ad5755_slew_rate_table)) | 
|  | dev_err(dev, | 
|  | "channel %d slew rate out of range selecting 64kHz\n", | 
|  | devnr); | 
|  |  | 
|  | pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1; | 
|  | for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) { | 
|  | if (tmparray[2] == ad5755_slew_step_table[i][0]) { | 
|  | pdata->dac[devnr].slew.step_size = | 
|  | ad5755_slew_step_table[i][1]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (i == ARRAY_SIZE(ad5755_slew_step_table)) | 
|  | dev_err(dev, | 
|  | "channel %d slew step size out of range selecting 1 LSB\n", | 
|  | devnr); | 
|  | } else { | 
|  | pdata->dac[devnr].slew.enable = false; | 
|  | pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; | 
|  | pdata->dac[devnr].slew.step_size = | 
|  | AD5755_SLEW_STEP_SIZE_1; | 
|  | } | 
|  | devnr++; | 
|  | } | 
|  |  | 
|  | return pdata; | 
|  |  | 
|  | error_out: | 
|  | fwnode_handle_put(pp); | 
|  | devm_kfree(dev, pdata); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static int ad5755_probe(struct spi_device *spi) | 
|  | { | 
|  | const struct ad5755_platform_data *pdata; | 
|  | 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 = spi_get_device_match_data(spi); | 
|  | st->spi = spi; | 
|  | st->pwr_down = 0xf; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | mutex_init(&st->lock); | 
|  |  | 
|  |  | 
|  | pdata = ad5755_parse_fw(&spi->dev); | 
|  | if (!pdata) { | 
|  | dev_warn(&spi->dev, "no firmware provided parameters? using default\n"); | 
|  | 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", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, | 
|  | { "ad5755-1", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, | 
|  | { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, | 
|  | { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, | 
|  | { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, | 
|  | {} | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(spi, ad5755_id); | 
|  |  | 
|  | static const struct of_device_id ad5755_of_match[] = { | 
|  | { .compatible = "adi,ad5755", &ad5755_chip_info_tbl[ID_AD5755] }, | 
|  | { .compatible = "adi,ad5755-1", &ad5755_chip_info_tbl[ID_AD5755] }, | 
|  | { .compatible = "adi,ad5757", &ad5755_chip_info_tbl[ID_AD5757] }, | 
|  | { .compatible = "adi,ad5735", &ad5755_chip_info_tbl[ID_AD5735] }, | 
|  | { .compatible = "adi,ad5737", &ad5755_chip_info_tbl[ID_AD5737] }, | 
|  | { } | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(of, ad5755_of_match); | 
|  |  | 
|  | static struct spi_driver ad5755_driver = { | 
|  | .driver = { | 
|  | .name = "ad5755", | 
|  | .of_match_table = ad5755_of_match, | 
|  | }, | 
|  | .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"); |