iio:ad5446: Add support for I2C based DACs
authorJean-Francois Dagenais <jeff.dagenais@gmail.com>
Tue, 21 Aug 2012 14:28:00 +0000 (15:28 +0100)
committerJonathan Cameron <jic23@kernel.org>
Mon, 3 Sep 2012 19:26:45 +0000 (20:26 +0100)
This patch adds support for I2C based single channel DACs to the ad5446
driver. Specifically AD5602, AD5612 and AD5622.

V1: from Lars-Peter Clausen <lars@metafoo.de>
V2: Split the device IDs into two enums and move them to the c file.

Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/dac/Kconfig
drivers/iio/dac/ad5446.c
drivers/iio/dac/ad5446.h

index 1be15fa9d618296978bc2809cbc4ed1ca41f98dd..293b61dcc5598ba0597ef69b995267426144cf57 100644 (file)
@@ -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.
index 2ca5059ef89ef16dce37b6c87448635d831433be..241665b8183be5bdcdf6d0590ff5b4c5015e6a6d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sysfs.h>
 #include <linux/list.h>
 #include <linux/spi/spi.h>
+#include <linux/i2c.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 #include <linux/module.h>
 
 #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,84 +120,7 @@ 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)
-
-static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
-       [ID_AD5444] = {
-               .channel = AD5446_CHANNEL(12, 16, 2),
-               .write = ad5446_write,
-       },
-       [ID_AD5446] = {
-               .channel = AD5446_CHANNEL(14, 16, 0),
-               .write = ad5446_write,
-       },
-       [ID_AD5450] = {
-               .channel = AD5446_CHANNEL(8, 16, 6),
-               .write = ad5446_write,
-       },
-       [ID_AD5451] = {
-               .channel = AD5446_CHANNEL(10, 16, 4),
-               .write = ad5446_write,
-       },
-       [ID_AD5541A] = {
-               .channel = AD5446_CHANNEL(16, 16, 0),
-               .write = ad5446_write,
-       },
-       [ID_AD5512A] = {
-               .channel = AD5446_CHANNEL(12, 16, 4),
-               .write = ad5446_write,
-       },
-       [ID_AD5553] = {
-               .channel = AD5446_CHANNEL(14, 16, 0),
-               .write = ad5446_write,
-       },
-       [ID_AD5601] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
-               .write = ad5446_write,
-       },
-       [ID_AD5611] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
-               .write = ad5446_write,
-       },
-       [ID_AD5621] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-               .write = ad5446_write,
-       },
-       [ID_AD5620_2500] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-               .int_vref_mv = 2500,
-               .write = ad5446_write,
-       },
-       [ID_AD5620_1250] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
-               .int_vref_mv = 1250,
-               .write = ad5446_write,
-       },
-       [ID_AD5640_2500] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
-               .int_vref_mv = 2500,
-               .write = ad5446_write,
-       },
-       [ID_AD5640_1250] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
-               .int_vref_mv = 1250,
-               .write = ad5446_write,
-       },
-       [ID_AD5660_2500] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-               .int_vref_mv = 2500,
-               .write = ad5660_write,
-       },
-       [ID_AD5660_1250] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-               .int_vref_mv = 1250,
-               .write = ad5660_write,
-       },
-       [ID_AD5662] = {
-               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
-               .write = ad5660_write,
-       },
-};
+       _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown)
 
 static int ad5446_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
@@ -272,14 +179,15 @@ static const struct iio_info ad5446_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad5446_probe(struct spi_device *spi)
+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(&spi->dev, "vcc");
+       reg = regulator_get(dev, "vcc");
        if (!IS_ERR(reg)) {
                ret = regulator_enable(reg);
                if (ret)
@@ -294,16 +202,15 @@ static int __devinit ad5446_probe(struct spi_device *spi)
                goto error_disable_reg;
        }
        st = iio_priv(indio_dev);
-       st->chip_info =
-               &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+       st->chip_info = chip_info;
 
-       spi_set_drvdata(spi, indio_dev);
+       dev_set_drvdata(dev, indio_dev);
        st->reg = reg;
-       st->spi = spi;
+       st->dev = dev;
 
-       /* 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;
+       /* 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;
@@ -316,7 +223,7 @@ static int __devinit ad5446_probe(struct spi_device *spi)
        else if (voltage_uv)
                st->vref_mv = voltage_uv / 1000;
        else
-               dev_warn(&spi->dev, "reference voltage unspecified\n");
+               dev_warn(dev, "reference voltage unspecified\n");
 
        ret = iio_device_register(indio_dev);
        if (ret)
@@ -336,9 +243,9 @@ error_put_reg:
        return ret;
 }
 
-static int ad5446_remove(struct spi_device *spi)
+static int ad5446_remove(struct device *dev)
 {
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ad5446_state *st = iio_priv(indio_dev);
 
        iio_device_unregister(indio_dev);
@@ -351,7 +258,133 @@ static int ad5446_remove(struct spi_device *spi)
        return 0;
 }
 
-static const struct spi_device_id ad5446_id[] = {
+#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,
+       },
+       [ID_AD5446] = {
+               .channel = AD5446_CHANNEL(14, 16, 0),
+               .write = ad5446_write,
+       },
+       [ID_AD5450] = {
+               .channel = AD5446_CHANNEL(8, 16, 6),
+               .write = ad5446_write,
+       },
+       [ID_AD5451] = {
+               .channel = AD5446_CHANNEL(10, 16, 4),
+               .write = ad5446_write,
+       },
+       [ID_AD5541A] = {
+               .channel = AD5446_CHANNEL(16, 16, 0),
+               .write = ad5446_write,
+       },
+       [ID_AD5512A] = {
+               .channel = AD5446_CHANNEL(12, 16, 4),
+               .write = ad5446_write,
+       },
+       [ID_AD5553] = {
+               .channel = AD5446_CHANNEL(14, 16, 0),
+               .write = ad5446_write,
+       },
+       [ID_AD5601] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+               .write = ad5446_write,
+       },
+       [ID_AD5611] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+               .write = ad5446_write,
+       },
+       [ID_AD5621] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+               .write = ad5446_write,
+       },
+       [ID_AD5620_2500] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+               .int_vref_mv = 2500,
+               .write = ad5446_write,
+       },
+       [ID_AD5620_1250] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+               .int_vref_mv = 1250,
+               .write = ad5446_write,
+       },
+       [ID_AD5640_2500] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+               .int_vref_mv = 2500,
+               .write = ad5446_write,
+       },
+       [ID_AD5640_1250] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+               .int_vref_mv = 1250,
+               .write = ad5446_write,
+       },
+       [ID_AD5660_2500] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+               .int_vref_mv = 2500,
+               .write = ad5660_write,
+       },
+       [ID_AD5660_1250] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+               .int_vref_mv = 1250,
+               .write = ad5660_write,
+       },
+       [ID_AD5662] = {
+               .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+               .write = ad5660_write,
+       },
+};
+
+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 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 struct spi_driver ad5446_driver = {
+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,
+};
+
+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,
+       },
 };
-module_spi_driver(ad5446_driver);
+
+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 <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
index 2934269a56d5ef906f26f1841606cd6ae8828f0f..6b7a1766c10937dabdf7e77f5db0dbe081c556c5 100644 (file)
@@ -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_ */