diff options
Diffstat (limited to 'drivers/iio/dac/ad5755.c')
| -rw-r--r-- | drivers/iio/dac/ad5755.c | 244 |
1 files changed, 160 insertions, 84 deletions
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 2d03cc89ba50..d0e5f35462b1 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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> @@ -14,10 +13,10 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/delay.h> -#include <linux/of.h> +#include <linux/property.h> + #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/platform_data/ad5755.h> #define AD5755_NUM_CHANNELS 4 @@ -64,6 +63,101 @@ #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 @@ -83,6 +177,7 @@ struct ad5755_chip_info { * @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 { @@ -91,16 +186,17 @@ struct ad5755_state { 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) requires the + * 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] ____cacheline_aligned; + } data[2] __aligned(IIO_DMA_MINALIGN); }; enum ad5755_type { @@ -110,7 +206,6 @@ enum ad5755_type { ID_AD5737, }; -#ifdef CONFIG_OF static const int ad5755_dcdc_freq_table[][2] = { { 250000, AD5755_DC_DC_FREQ_250kHZ }, { 410000, AD5755_DC_DC_FREQ_410kHZ }, @@ -153,7 +248,6 @@ static const int ad5755_slew_step_table[][2] = { { 2, AD5755_SLEW_STEP_SIZE_2 }, { 1, AD5755_SLEW_STEP_SIZE_1 }, }; -#endif static int ad5755_write_unlocked(struct iio_dev *indio_dev, unsigned int reg, unsigned int val) @@ -175,11 +269,12 @@ static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev, 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(&indio_dev->mlock); + mutex_lock(&st->lock); ret = ad5755_write_unlocked(indio_dev, reg, val); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret; } @@ -187,11 +282,12 @@ static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg, 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(&indio_dev->mlock); + mutex_lock(&st->lock); ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret; } @@ -212,7 +308,7 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) }, }; - mutex_lock(&indio_dev->mlock); + 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); @@ -221,7 +317,7 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret; } @@ -247,7 +343,7 @@ static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev, struct ad5755_state *st = iio_priv(indio_dev); unsigned int mask = BIT(channel); - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); if ((bool)(st->pwr_down & mask) == pwr_down) goto out_unlock; @@ -267,7 +363,7 @@ static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev, } out_unlock: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return 0; } @@ -396,8 +492,8 @@ static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv, { struct ad5755_state *st = iio_priv(indio_dev); - return sprintf(buf, "%d\n", - (bool)(st->pwr_down & (1 << chan->channel))); + 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, @@ -406,7 +502,7 @@ static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv, bool pwr_down; int ret; - ret = strtobool(buf, &pwr_down); + ret = kstrtobool(buf, &pwr_down); if (ret) return ret; @@ -426,7 +522,7 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { .write = ad5755_write_powerdown, .shared = IIO_SEPARATE, }, - { }, + { } }; #define AD5755_CHANNEL(_bits) { \ @@ -601,30 +697,28 @@ static const struct ad5755_platform_data ad5755_default_pdata = { }, }; -#ifdef CONFIG_OF -static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) +static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) { - struct device_node *np = dev->of_node; - struct device_node *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 = - of_property_read_bool(np, "adi,ext-dc-dc-compenstation-resistor"); + device_property_read_bool(dev, "adi,ext-dc-dc-compenstation-resistor"); - if (!of_property_read_u32(np, "adi,dc-dc-phase", &tmp)) - pdata->dc_dc_phase = tmp; - else - pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE; + 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 (!of_property_read_u32(np, "adi,dc-dc-freq-hz", &tmp)) { + 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]; @@ -632,46 +726,43 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) } } - if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) { + if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) dev_err(dev, - "adi,dc-dc-freq out of range selecting 410kHz"); - } + "adi,dc-dc-freq out of range selecting 410kHz\n"); } pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V; - if (!of_property_read_u32(np, "adi,dc-dc-max-microvolt", &tmp)) { + 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)) { + if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) dev_err(dev, - "adi,dc-dc-maxv out of range selecting 23V"); - } + "adi,dc-dc-maxv out of range selecting 23V\n"); } devnr = 0; - for_each_child_of_node(np, pp) { + device_for_each_child_node_scoped(dev, pp) { if (devnr >= AD5755_NUM_CHANNELS) { dev_err(dev, - "There is to many channels defined in DT\n"); - goto error_out; + "There are too many channels defined in DT\n"); + devm_kfree(dev, pdata); + return NULL; } - if (!of_property_read_u32(pp, "adi,mode", &tmp)) - pdata->dac[devnr].mode = tmp; - else - pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA; + 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 = - of_property_read_bool(pp, "adi,ext-current-sense-resistor"); + fwnode_property_read_bool(pp, "adi,ext-current-sense-resistor"); pdata->dac[devnr].enable_voltage_overrange = - of_property_read_bool(pp, "adi,enable-voltage-overrange"); + fwnode_property_read_bool(pp, "adi,enable-voltage-overrange"); - if (!of_property_read_u32_array(pp, "adi,slew", tmparray, 3)) { + 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; @@ -682,11 +773,10 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) break; } } - if (i == ARRAY_SIZE(ad5755_slew_rate_table)) { + if (i == ARRAY_SIZE(ad5755_slew_rate_table)) dev_err(dev, - "channel %d slew rate out of range selecting 64kHz", + "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++) { @@ -696,11 +786,10 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) break; } } - if (i == ARRAY_SIZE(ad5755_slew_step_table)) { + if (i == ARRAY_SIZE(ad5755_slew_step_table)) dev_err(dev, - "channel %d slew step size out of range selecting 1 LSB", + "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; @@ -711,23 +800,11 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) } return pdata; - - error_out: - devm_kfree(dev, pdata); - return NULL; } -#else -static -struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) -{ - return NULL; -} -#endif 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); + const struct ad5755_platform_data *pdata; struct iio_dev *indio_dev; struct ad5755_state *st; int ret; @@ -741,23 +818,21 @@ static int ad5755_probe(struct spi_device *spi) st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - st->chip_info = &ad5755_chip_info_tbl[type]; + st->chip_info = spi_get_device_match_data(spi); 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 (spi->dev.of_node) - pdata = ad5755_parse_dt(&spi->dev); - else - pdata = spi->dev.platform_data; + mutex_init(&st->lock); + + pdata = ad5755_parse_fw(&spi->dev); if (!pdata) { - dev_warn(&spi->dev, "no platform data? using default\n"); + dev_warn(&spi->dev, "no firmware provided parameters? using default\n"); pdata = &ad5755_default_pdata; } @@ -773,21 +848,21 @@ static int ad5755_probe(struct spi_device *spi) } static const struct spi_device_id ad5755_id[] = { - { "ad5755", ID_AD5755 }, - { "ad5755-1", ID_AD5755 }, - { "ad5757", ID_AD5757 }, - { "ad5735", ID_AD5735 }, - { "ad5737", ID_AD5737 }, - {} + { "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" }, - { .compatible = "adi,ad5755-1" }, - { .compatible = "adi,ad5757" }, - { .compatible = "adi,ad5735" }, - { .compatible = "adi,ad5737" }, + { .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); @@ -795,6 +870,7 @@ 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, |
