diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 1be15fa9d618..293b61dcc559 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -57,11 +57,12 @@ config AD5624R_SPI config AD5446 tristate "Analog Devices AD5446 and similar single channel DACs driver" - depends on SPI + depends on (SPI_MASTER || I2C) help - Say yes here to build support for Analog Devices AD5444, AD5446, AD5450, - AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, - AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 DACs. + Say yes here to build support for Analog Devices AD5602, AD5612, AD5622, + AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, + AD5543, AD5553, AD5601, AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 + DACs. To compile this driver as a module, choose M here: the module will be called ad5446. diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 2ca5059ef89e..241665b8183b 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,23 +24,6 @@ #include "ad5446.h" -static int ad5446_write(struct ad5446_state *st, unsigned val) -{ - __be16 data = cpu_to_be16(val); - return spi_write(st->spi, &data, sizeof(data)); -} - -static int ad5660_write(struct ad5446_state *st, unsigned val) -{ - uint8_t data[3]; - - data[0] = (val >> 16) & 0xFF; - data[1] = (val >> 8) & 0xFF; - data[2] = val & 0xFF; - - return spi_write(st->spi, data, sizeof(data)); -} - static const char * const ad5446_powerdown_modes[] = { "1kohm_to_gnd", "100kohm_to_gnd", "three_state" }; @@ -110,7 +94,7 @@ static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, return ret ? ret : len; } -static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = { +static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { { .name = "powerdown", .read = ad5446_read_dac_powerdown, @@ -136,9 +120,194 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = { _AD5446_CHANNEL(bits, storage, shift, NULL) #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ - _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown) + _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) -static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { +static int ad5446_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct ad5446_state *st = iio_priv(indio_dev); + unsigned long scale_uv; + + switch (m) { + case IIO_CHAN_INFO_RAW: + *val = st->cached_val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + + } + return -EINVAL; +} + +static int ad5446_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad5446_state *st = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val >= (1 << chan->scan_type.realbits) || val < 0) + return -EINVAL; + + val <<= chan->scan_type.shift; + mutex_lock(&indio_dev->mlock); + st->cached_val = val; + if (!st->pwr_down) + ret = st->chip_info->write(st, val); + mutex_unlock(&indio_dev->mlock); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info ad5446_info = { + .read_raw = ad5446_read_raw, + .write_raw = ad5446_write_raw, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5446_probe(struct device *dev, const char *name, + const struct ad5446_chip_info *chip_info) +{ + struct ad5446_state *st; + struct iio_dev *indio_dev; + struct regulator *reg; + int ret, voltage_uv = 0; + + reg = regulator_get(dev, "vcc"); + if (!IS_ERR(reg)) { + ret = regulator_enable(reg); + if (ret) + goto error_put_reg; + + voltage_uv = regulator_get_voltage(reg); + } + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + st = iio_priv(indio_dev); + st->chip_info = chip_info; + + dev_set_drvdata(dev, indio_dev); + st->reg = reg; + st->dev = dev; + + /* Establish that the iio_dev is a child of the device */ + indio_dev->dev.parent = dev; + indio_dev->name = name; + indio_dev->info = &ad5446_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &st->chip_info->channel; + indio_dev->num_channels = 1; + + st->pwr_down_mode = MODE_PWRDWN_1k; + + if (st->chip_info->int_vref_mv) + st->vref_mv = st->chip_info->int_vref_mv; + else if (voltage_uv) + st->vref_mv = voltage_uv / 1000; + else + dev_warn(dev, "reference voltage unspecified\n"); + + ret = iio_device_register(indio_dev); + if (ret) + goto error_free_device; + + return 0; + +error_free_device: + iio_device_free(indio_dev); +error_disable_reg: + if (!IS_ERR(reg)) + regulator_disable(reg); +error_put_reg: + if (!IS_ERR(reg)) + regulator_put(reg); + + return ret; +} + +static int ad5446_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int ad5446_write(struct ad5446_state *st, unsigned val) +{ + struct spi_device *spi = to_spi_device(st->dev); + __be16 data = cpu_to_be16(val); + + return spi_write(spi, &data, sizeof(data)); +} + +static int ad5660_write(struct ad5446_state *st, unsigned val) +{ + struct spi_device *spi = to_spi_device(st->dev); + uint8_t data[3]; + + data[0] = (val >> 16) & 0xFF; + data[1] = (val >> 8) & 0xFF; + data[2] = val & 0xFF; + + return spi_write(spi, data, sizeof(data)); +} + +/** + * ad5446_supported_spi_device_ids: + * The AD5620/40/60 parts are available in different fixed internal reference + * voltage options. The actual part numbers may look differently + * (and a bit cryptic), however this style is used to make clear which + * parts are supported here. + */ +enum ad5446_supported_spi_device_ids { + ID_AD5444, + ID_AD5446, + ID_AD5450, + ID_AD5451, + ID_AD5541A, + ID_AD5512A, + ID_AD5553, + ID_AD5601, + ID_AD5611, + ID_AD5621, + ID_AD5620_2500, + ID_AD5620_1250, + ID_AD5640_2500, + ID_AD5640_1250, + ID_AD5660_2500, + ID_AD5660_1250, + ID_AD5662, +}; + +static const struct ad5446_chip_info ad5446_spi_chip_info[] = { [ID_AD5444] = { .channel = AD5446_CHANNEL(12, 16, 2), .write = ad5446_write, @@ -215,143 +384,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { }, }; -static int ad5446_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - struct ad5446_state *st = iio_priv(indio_dev); - unsigned long scale_uv; - - switch (m) { - case IIO_CHAN_INFO_RAW: - *val = st->cached_val; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; - *val = scale_uv / 1000; - *val2 = (scale_uv % 1000) * 1000; - return IIO_VAL_INT_PLUS_MICRO; - - } - return -EINVAL; -} - -static int ad5446_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct ad5446_state *st = iio_priv(indio_dev); - int ret = 0; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (val >= (1 << chan->scan_type.realbits) || val < 0) - return -EINVAL; - - val <<= chan->scan_type.shift; - mutex_lock(&indio_dev->mlock); - st->cached_val = val; - if (!st->pwr_down) - ret = st->chip_info->write(st, val); - mutex_unlock(&indio_dev->mlock); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct iio_info ad5446_info = { - .read_raw = ad5446_read_raw, - .write_raw = ad5446_write_raw, - .driver_module = THIS_MODULE, -}; - -static int __devinit ad5446_probe(struct spi_device *spi) -{ - struct ad5446_state *st; - struct iio_dev *indio_dev; - struct regulator *reg; - int ret, voltage_uv = 0; - - reg = regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) - goto error_put_reg; - - voltage_uv = regulator_get_voltage(reg); - } - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_reg; - } - st = iio_priv(indio_dev); - st->chip_info = - &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - - spi_set_drvdata(spi, indio_dev); - st->reg = reg; - st->spi = spi; - - /* Establish that the iio_dev is a child of the spi device */ - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->info = &ad5446_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = &st->chip_info->channel; - indio_dev->num_channels = 1; - - st->pwr_down_mode = MODE_PWRDWN_1k; - - if (st->chip_info->int_vref_mv) - st->vref_mv = st->chip_info->int_vref_mv; - else if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - dev_warn(&spi->dev, "reference voltage unspecified\n"); - - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_device; - - return 0; - -error_free_device: - iio_device_free(indio_dev); -error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); -error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); - - return ret; -} - -static int ad5446_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5446_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) { - regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id ad5446_id[] = { +static const struct spi_device_id ad5446_spi_ids[] = { {"ad5444", ID_AD5444}, {"ad5446", ID_AD5446}, {"ad5450", ID_AD5450}, @@ -375,18 +408,157 @@ static const struct spi_device_id ad5446_id[] = { {"ad5662", ID_AD5662}, {} }; -MODULE_DEVICE_TABLE(spi, ad5446_id); +MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); -static struct spi_driver ad5446_driver = { +static int __devinit ad5446_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + return ad5446_probe(&spi->dev, id->name, + &ad5446_spi_chip_info[id->driver_data]); +} + +static int __devexit ad5446_spi_remove(struct spi_device *spi) +{ + return ad5446_remove(&spi->dev); +} + +static struct spi_driver ad5446_spi_driver = { .driver = { .name = "ad5446", .owner = THIS_MODULE, }, - .probe = ad5446_probe, - .remove = __devexit_p(ad5446_remove), - .id_table = ad5446_id, + .probe = ad5446_spi_probe, + .remove = __devexit_p(ad5446_spi_remove), + .id_table = ad5446_spi_ids, }; -module_spi_driver(ad5446_driver); + +static int __init ad5446_spi_register_driver(void) +{ + return spi_register_driver(&ad5446_spi_driver); +} + +static void ad5446_spi_unregister_driver(void) +{ + spi_unregister_driver(&ad5446_spi_driver); +} + +#else + +static inline int ad5446_spi_register_driver(void) { return 0; } +static inline void ad5446_spi_unregister_driver(void) { } + +#endif + +#if IS_ENABLED(CONFIG_I2C) + +static int ad5622_write(struct ad5446_state *st, unsigned val) +{ + struct i2c_client *client = to_i2c_client(st->dev); + __be16 data = cpu_to_be16(val); + + return i2c_master_send(client, (char *)&data, sizeof(data)); +} + +/** + * ad5446_supported_i2c_device_ids: + * The AD5620/40/60 parts are available in different fixed internal reference + * voltage options. The actual part numbers may look differently + * (and a bit cryptic), however this style is used to make clear which + * parts are supported here. + */ +enum ad5446_supported_i2c_device_ids { + ID_AD5602, + ID_AD5612, + ID_AD5622, +}; + +static const struct ad5446_chip_info ad5446_i2c_chip_info[] = { + [ID_AD5602] = { + .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), + .write = ad5622_write, + }, + [ID_AD5612] = { + .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), + .write = ad5622_write, + }, + [ID_AD5622] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), + .write = ad5622_write, + }, +}; + +static int __devinit ad5446_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return ad5446_probe(&i2c->dev, id->name, + &ad5446_i2c_chip_info[id->driver_data]); +} + +static int __devexit ad5446_i2c_remove(struct i2c_client *i2c) +{ + return ad5446_remove(&i2c->dev); +} + +static const struct i2c_device_id ad5446_i2c_ids[] = { + {"ad5602", ID_AD5602}, + {"ad5612", ID_AD5612}, + {"ad5622", ID_AD5622}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); + +static struct i2c_driver ad5446_i2c_driver = { + .driver = { + .name = "ad5446", + .owner = THIS_MODULE, + }, + .probe = ad5446_i2c_probe, + .remove = __devexit_p(ad5446_i2c_remove), + .id_table = ad5446_i2c_ids, +}; + +static int __init ad5446_i2c_register_driver(void) +{ + return i2c_add_driver(&ad5446_i2c_driver); +} + +static void __exit ad5446_i2c_unregister_driver(void) +{ + i2c_del_driver(&ad5446_i2c_driver); +} + +#else + +static inline int ad5446_i2c_register_driver(void) { return 0; } +static inline void ad5446_i2c_unregister_driver(void) { } + +#endif + +static int __init ad5446_init(void) +{ + int ret; + + ret = ad5446_spi_register_driver(); + if (ret) + return ret; + + ret = ad5446_i2c_register_driver(); + if (ret) { + ad5446_spi_unregister_driver(); + return ret; + } + + return 0; +} +module_init(ad5446_init); + +static void __exit ad5446_exit(void) +{ + ad5446_i2c_unregister_driver(); + ad5446_spi_unregister_driver(); +} +module_exit(ad5446_exit); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); diff --git a/drivers/iio/dac/ad5446.h b/drivers/iio/dac/ad5446.h index 2934269a56d5..6b7a1766c109 100644 --- a/drivers/iio/dac/ad5446.h +++ b/drivers/iio/dac/ad5446.h @@ -38,7 +38,7 @@ */ struct ad5446_state { - struct spi_device *spi; + struct device *dev; const struct ad5446_chip_info *chip_info; struct regulator *reg; unsigned short vref_mv; @@ -60,32 +60,5 @@ struct ad5446_chip_info { int (*write)(struct ad5446_state *st, unsigned val); }; -/** - * ad5446_supported_device_ids: - * The AD5620/40/60 parts are available in different fixed internal reference - * voltage options. The actual part numbers may look differently - * (and a bit cryptic), however this style is used to make clear which - * parts are supported here. - */ - -enum ad5446_supported_device_ids { - ID_AD5444, - ID_AD5446, - ID_AD5450, - ID_AD5451, - ID_AD5541A, - ID_AD5512A, - ID_AD5553, - ID_AD5601, - ID_AD5611, - ID_AD5621, - ID_AD5620_2500, - ID_AD5620_1250, - ID_AD5640_2500, - ID_AD5640_1250, - ID_AD5660_2500, - ID_AD5660_1250, - ID_AD5662, -}; #endif /* IIO_DAC_AD5446_H_ */