summaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-29 09:49:28 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-29 09:49:28 -0700
commit3dc50c1af30bf79c4fca3065acfb34adf05e90c2 (patch)
tree38677ba815b1ec8f3c4ec3eea5dafb34f294b5f7 /drivers/iio
parentac4ddad67acb9f67b42902939df64980fcbdbae5 (diff)
parent9dd4694dafbd8b44ac4ca740beede18ca67d725f (diff)
downloadtalos-op-linux-3dc50c1af30bf79c4fca3065acfb34adf05e90c2.tar.gz
talos-op-linux-3dc50c1af30bf79c4fca3065acfb34adf05e90c2.zip
Merge tag 'iio-for-3.17b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: Second round of new drivers and cleanups for IIO in the 3.17 cycle. New drivers * mcp4902, mcp4912 and mcp4922 SPI DAC driver. * max1027, max1029 and max1031 SPI ADC driver. Cleanups * cm32181 - use devm APIs to simplify error paths. * ak8975 - use devm APIs to simplify error paths. * ad9850 - drop some unused defines and an unnecessary goto. * hmc5843 - add missing devices to the device id table and the documentation. * ad9832 - small formatting cleanups. * sca3000 - hide direct use of the stufftoread element by adding a data_available function. This is a precursor for the addition of buffer watermarks to the subsystem but stands as a good cleanup on its own.
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/adc/Kconfig9
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/max1027.c521
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/mcp4922.c216
-rw-r--r--drivers/iio/industrialio-buffer.c5
-rw-r--r--drivers/iio/light/cm32181.c11
-rw-r--r--drivers/iio/magnetometer/ak8975.c58
9 files changed, 774 insertions, 58 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a80d23628f14..20a7073f1dd6 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -131,6 +131,15 @@ config LP8788_ADC
help
Say yes here to build support for TI LP8788 ADC.
+config MAX1027
+ tristate "Maxim max1027 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Maxim SPI ADC models
+ max1027, max1029 and max1031.
+
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 9d60f2deaaaf..38cf5c3f5631 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
+obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
new file mode 100644
index 000000000000..87ee1c7d0b54
--- /dev/null
+++ b/drivers/iio/adc/max1027.c
@@ -0,0 +1,521 @@
+ /*
+ * iio/adc/max1027.c
+ * Copyright (C) 2014 Philippe Reynes
+ *
+ * based on linux/drivers/iio/ad7923.c
+ * Copyright 2011 Analog Devices Inc (from AD7923 Driver)
+ * Copyright 2012 CS Systemes d'Information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * max1027.c
+ *
+ * Partial support for max1027 and similar chips.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX1027_CONV_REG BIT(7)
+#define MAX1027_SETUP_REG BIT(6)
+#define MAX1027_AVG_REG BIT(5)
+#define MAX1027_RST_REG BIT(4)
+
+/* conversion register */
+#define MAX1027_TEMP BIT(0)
+#define MAX1027_SCAN_0_N (0x00 << 1)
+#define MAX1027_SCAN_N_M (0x01 << 1)
+#define MAX1027_SCAN_N (0x02 << 1)
+#define MAX1027_NOSCAN (0x03 << 1)
+#define MAX1027_CHAN(n) ((n) << 3)
+
+/* setup register */
+#define MAX1027_UNIPOLAR 0x02
+#define MAX1027_BIPOLAR 0x03
+#define MAX1027_REF_MODE0 (0x00 << 2)
+#define MAX1027_REF_MODE1 (0x01 << 2)
+#define MAX1027_REF_MODE2 (0x02 << 2)
+#define MAX1027_REF_MODE3 (0x03 << 2)
+#define MAX1027_CKS_MODE0 (0x00 << 4)
+#define MAX1027_CKS_MODE1 (0x01 << 4)
+#define MAX1027_CKS_MODE2 (0x02 << 4)
+#define MAX1027_CKS_MODE3 (0x03 << 4)
+
+/* averaging register */
+#define MAX1027_NSCAN_4 0x00
+#define MAX1027_NSCAN_8 0x01
+#define MAX1027_NSCAN_12 0x02
+#define MAX1027_NSCAN_16 0x03
+#define MAX1027_NAVG_4 (0x00 << 2)
+#define MAX1027_NAVG_8 (0x01 << 2)
+#define MAX1027_NAVG_16 (0x02 << 2)
+#define MAX1027_NAVG_32 (0x03 << 2)
+#define MAX1027_AVG_EN BIT(4)
+
+enum max1027_id {
+ max1027,
+ max1029,
+ max1031,
+};
+
+static const struct spi_device_id max1027_id[] = {
+ {"max1027", max1027},
+ {"max1029", max1029},
+ {"max1031", max1031},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, max1027_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id max1027_adc_dt_ids[] = {
+ { .compatible = "maxim,max1027" },
+ { .compatible = "maxim,max1029" },
+ { .compatible = "maxim,max1031" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
+#endif
+
+#define MAX1027_V_CHAN(index) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = index + 1, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 10, \
+ .storagebits = 16, \
+ .shift = 2, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define MAX1027_T_CHAN \
+ { \
+ .type = IIO_TEMP, \
+ .channel = 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = 0, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+static const struct iio_chan_spec max1027_channels[] = {
+ MAX1027_T_CHAN,
+ MAX1027_V_CHAN(0),
+ MAX1027_V_CHAN(1),
+ MAX1027_V_CHAN(2),
+ MAX1027_V_CHAN(3),
+ MAX1027_V_CHAN(4),
+ MAX1027_V_CHAN(5),
+ MAX1027_V_CHAN(6),
+ MAX1027_V_CHAN(7)
+};
+
+static const struct iio_chan_spec max1029_channels[] = {
+ MAX1027_T_CHAN,
+ MAX1027_V_CHAN(0),
+ MAX1027_V_CHAN(1),
+ MAX1027_V_CHAN(2),
+ MAX1027_V_CHAN(3),
+ MAX1027_V_CHAN(4),
+ MAX1027_V_CHAN(5),
+ MAX1027_V_CHAN(6),
+ MAX1027_V_CHAN(7),
+ MAX1027_V_CHAN(8),
+ MAX1027_V_CHAN(9),
+ MAX1027_V_CHAN(10),
+ MAX1027_V_CHAN(11)
+};
+
+static const struct iio_chan_spec max1031_channels[] = {
+ MAX1027_T_CHAN,
+ MAX1027_V_CHAN(0),
+ MAX1027_V_CHAN(1),
+ MAX1027_V_CHAN(2),
+ MAX1027_V_CHAN(3),
+ MAX1027_V_CHAN(4),
+ MAX1027_V_CHAN(5),
+ MAX1027_V_CHAN(6),
+ MAX1027_V_CHAN(7),
+ MAX1027_V_CHAN(8),
+ MAX1027_V_CHAN(9),
+ MAX1027_V_CHAN(10),
+ MAX1027_V_CHAN(11),
+ MAX1027_V_CHAN(12),
+ MAX1027_V_CHAN(13),
+ MAX1027_V_CHAN(14),
+ MAX1027_V_CHAN(15)
+};
+
+static const unsigned long max1027_available_scan_masks[] = {
+ 0x000001ff,
+ 0x00000000,
+};
+
+static const unsigned long max1029_available_scan_masks[] = {
+ 0x00001fff,
+ 0x00000000,
+};
+
+static const unsigned long max1031_available_scan_masks[] = {
+ 0x0001ffff,
+ 0x00000000,
+};
+
+struct max1027_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const unsigned long *available_scan_masks;
+};
+
+static const struct max1027_chip_info max1027_chip_info_tbl[] = {
+ [max1027] = {
+ .channels = max1027_channels,
+ .num_channels = ARRAY_SIZE(max1027_channels),
+ .available_scan_masks = max1027_available_scan_masks,
+ },
+ [max1029] = {
+ .channels = max1029_channels,
+ .num_channels = ARRAY_SIZE(max1029_channels),
+ .available_scan_masks = max1029_available_scan_masks,
+ },
+ [max1031] = {
+ .channels = max1031_channels,
+ .num_channels = ARRAY_SIZE(max1031_channels),
+ .available_scan_masks = max1031_available_scan_masks,
+ },
+};
+
+struct max1027_state {
+ const struct max1027_chip_info *info;
+ struct spi_device *spi;
+ struct iio_trigger *trig;
+ __be16 *buffer;
+ struct mutex lock;
+
+ u8 reg ____cacheline_aligned;
+};
+
+static int max1027_read_single_value(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ int ret;
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev)) {
+ dev_warn(&indio_dev->dev, "trigger mode already enabled");
+ return -EBUSY;
+ }
+
+ /* Start acquisition on conversion register write */
+ st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev,
+ "Failed to configure setup register\n");
+ return ret;
+ }
+
+ /* Configure conversion register with the requested chan */
+ st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) |
+ MAX1027_NOSCAN | !!(chan->type == IIO_TEMP);
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev,
+ "Failed to configure conversion register\n");
+ return ret;
+ }
+
+ /*
+ * For an unknown reason, when we use the mode "10" (write
+ * conversion register), the interrupt doesn't occur every time.
+ * So we just wait 1 ms.
+ */
+ mdelay(1);
+
+ /* Read result */
+ ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2);
+ if (ret < 0)
+ return ret;
+
+ *val = be16_to_cpu(st->buffer[0]);
+
+ return IIO_VAL_INT;
+}
+
+static int max1027_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret = 0;
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ mutex_lock(&st->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = max1027_read_single_value(indio_dev, chan, val);
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_TEMP:
+ *val = 1;
+ *val2 = 8;
+ ret = IIO_VAL_FRACTIONAL;
+ break;
+ case IIO_VOLTAGE:
+ *val = 2500;
+ *val2 = 10;
+ ret = IIO_VAL_FRACTIONAL_LOG2;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct max1027_state *st = iio_priv(indio_dev);
+ u8 *val = (u8 *)st->buffer;
+
+ if (readval != NULL)
+ return -EINVAL;
+
+ *val = (u8)writeval;
+ return spi_write(st->spi, val, 1);
+}
+
+static int max1027_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ if (st->trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct max1027_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (state) {
+ /* Start acquisition on cnvst */
+ st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 |
+ MAX1027_REF_MODE2;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Scan from 0 to max */
+ st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) |
+ MAX1027_SCAN_N_M | MAX1027_TEMP;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* Start acquisition on conversion register write */
+ st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 |
+ MAX1027_REF_MODE2;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max1027_validate_device(struct iio_trigger *trig,
+ struct iio_dev *indio_dev)
+{
+ struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+
+ if (indio != indio_dev)
+ return -EINVAL;
+
+ return 0;
+}
+
+static irqreturn_t max1027_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = (struct iio_poll_func *)private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private);
+
+ /* fill buffer with all channel */
+ spi_read(st->spi, st->buffer, indio_dev->masklength * 2);
+
+ iio_push_to_buffers(indio_dev, st->buffer);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_trigger_ops max1027_trigger_ops = {
+ .owner = THIS_MODULE,
+ .validate_device = &max1027_validate_device,
+ .set_trigger_state = &max1027_set_trigger_state,
+};
+
+static const struct iio_info max1027_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &max1027_read_raw,
+ .validate_trigger = &max1027_validate_trigger,
+ .debugfs_reg_access = &max1027_debugfs_reg_access,
+};
+
+static int max1027_probe(struct spi_device *spi)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct max1027_state *st;
+
+ pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi);
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (indio_dev == NULL) {
+ pr_err("Can't allocate iio device\n");
+ return -ENOMEM;
+ }
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ mutex_init(&st->lock);
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &max1027_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->info->channels;
+ indio_dev->num_channels = st->info->num_channels;
+ indio_dev->available_scan_masks = st->info->available_scan_masks;
+
+ st->buffer = devm_kmalloc(&indio_dev->dev,
+ indio_dev->num_channels * 2,
+ GFP_KERNEL);
+ if (st->buffer == NULL) {
+ dev_err(&indio_dev->dev, "Can't allocate bufffer\n");
+ return -ENOMEM;
+ }
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ &max1027_trigger_handler, NULL);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to setup buffer\n");
+ return ret;
+ }
+
+ st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
+ indio_dev->name);
+ if (st->trig == NULL) {
+ ret = -ENOMEM;
+ dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
+ goto fail_trigger_alloc;
+ }
+
+ st->trig->ops = &max1027_trigger_ops;
+ st->trig->dev.parent = &spi->dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ iio_trigger_register(st->trig);
+
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq,
+ iio_trigger_generic_data_rdy_poll,
+ NULL,
+ IRQF_TRIGGER_FALLING,
+ spi->dev.driver->name, st->trig);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
+ goto fail_dev_register;
+ }
+
+ /* Disable averaging */
+ st->reg = MAX1027_AVG_REG;
+ ret = spi_write(st->spi, &st->reg, 1);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to configure averaging register\n");
+ goto fail_dev_register;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to register iio device\n");
+ goto fail_dev_register;
+ }
+
+ return 0;
+
+fail_dev_register:
+fail_trigger_alloc:
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ return ret;
+}
+
+static int max1027_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ return 0;
+}
+
+static struct spi_driver max1027_driver = {
+ .driver = {
+ .name = "max1027",
+ .owner = THIS_MODULE,
+ },
+ .probe = max1027_probe,
+ .remove = max1027_remove,
+ .id_table = max1027_id,
+};
+module_spi_driver(max1027_driver);
+
+MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
+MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index f378ca8033db..f278eff42a4c 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -163,4 +163,14 @@ config MCP4725
To compile this driver as a module, choose M here: the module
will be called mcp4725.
+config MCP4922
+ tristate "MCP4902, MCP4912, MCP4922 DAC driver"
+ depends on SPI
+ help
+ Say yes here to build the driver for the Microchip MCP4902
+ MCP4912, and MCP4922 DAC devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcp4922.
+
endmenu
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index bb84ad64463f..10107640bb46 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MCP4725) += mcp4725.o
+obj-$(CONFIG_MCP4922) += mcp4922.o
diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c
new file mode 100644
index 000000000000..92cf4ca6981d
--- /dev/null
+++ b/drivers/iio/dac/mcp4922.c
@@ -0,0 +1,216 @@
+/*
+ * mcp4922.c
+ *
+ * Driver for Microchip Digital to Analog Converters.
+ * Supports MCP4902, MCP4912, and MCP4922.
+ *
+ * Copyright (c) 2014 EMAC Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/bitops.h>
+
+#define MCP4922_NUM_CHANNELS 2
+
+enum mcp4922_supported_device_ids {
+ ID_MCP4902,
+ ID_MCP4912,
+ ID_MCP4922,
+};
+
+struct mcp4922_state {
+ struct spi_device *spi;
+ unsigned int value[MCP4922_NUM_CHANNELS];
+ unsigned int vref_mv;
+ struct regulator *vref_reg;
+ u8 mosi[2] ____cacheline_aligned;
+};
+
+#define MCP4922_CHAN(chan, bits) { \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 12 - (bits), \
+ }, \
+}
+
+static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val)
+{
+ state->mosi[1] = val & 0xff;
+ state->mosi[0] = (addr == 0) ? 0x00 : 0x80;
+ state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f);
+
+ return spi_write(state->spi, state->mosi, 2);
+}
+
+static int mcp4922_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct mcp4922_state *state = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ *val = state->value[chan->channel];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = state->vref_mv;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp4922_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct mcp4922_state *state = iio_priv(indio_dev);
+
+ if (val2 != 0)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > GENMASK(chan->scan_type.realbits-1, 0))
+ return -EINVAL;
+ val <<= chan->scan_type.shift;
+ state->value[chan->channel] = val;
+ return mcp4922_spi_write(state, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = {
+ [ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) },
+ [ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) },
+ [ID_MCP4922] = { MCP4922_CHAN(0, 12), MCP4922_CHAN(1, 12) },
+};
+
+static const struct iio_info mcp4922_info = {
+ .read_raw = &mcp4922_read_raw,
+ .write_raw = &mcp4922_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int mcp4922_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct mcp4922_state *state;
+ const struct spi_device_id *id;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+ state->spi = spi;
+ state->vref_reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(state->vref_reg)) {
+ dev_err(&spi->dev, "Vref regulator not specified\n");
+ return PTR_ERR(state->vref_reg);
+ }
+
+ ret = regulator_enable(state->vref_reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable vref regulator: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regulator_get_voltage(state->vref_reg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Failed to read vref regulator: %d\n",
+ ret);
+ goto error_disable_reg;
+ }
+ state->vref_mv = ret / 1000;
+
+ spi_set_drvdata(spi, indio_dev);
+ id = spi_get_device_id(spi);
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &mcp4922_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mcp4922_channels[id->driver_data];
+ indio_dev->num_channels = MCP4922_NUM_CHANNELS;
+ indio_dev->name = id->name;
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to register iio device: %d\n",
+ ret);
+ goto error_disable_reg;
+ }
+
+ return 0;
+
+error_disable_reg:
+ regulator_disable(state->vref_reg);
+
+ return ret;
+}
+
+static int mcp4922_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct mcp4922_state *state;
+
+ iio_device_unregister(indio_dev);
+ state = iio_priv(indio_dev);
+ regulator_disable(state->vref_reg);
+
+ return 0;
+}
+
+static const struct spi_device_id mcp4922_id[] = {
+ {"mcp4902", ID_MCP4902},
+ {"mcp4912", ID_MCP4912},
+ {"mcp4922", ID_MCP4922},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, mcp4922_id);
+
+static struct spi_driver mcp4922_driver = {
+ .driver = {
+ .name = "mcp4922",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcp4922_probe,
+ .remove = mcp4922_remove,
+ .id_table = mcp4922_id,
+};
+module_spi_driver(mcp4922_driver);
+
+MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
+MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 36b1ae92e239..2952ee038477 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -39,10 +39,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
static bool iio_buffer_data_available(struct iio_buffer *buf)
{
- if (buf->access->data_available)
- return buf->access->data_available(buf);
-
- return buf->stufftoread;
+ return buf->access->data_available(buf);
}
/**
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index d976e6ce60db..ad36b294e4d5 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -331,7 +331,7 @@ static int cm32181_probe(struct i2c_client *client,
return ret;
}
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(&client->dev, indio_dev);
if (ret) {
dev_err(&client->dev,
"%s: regist device failed\n",
@@ -342,14 +342,6 @@ static int cm32181_probe(struct i2c_client *client,
return 0;
}
-static int cm32181_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- return 0;
-}
-
static const struct i2c_device_id cm32181_id[] = {
{ "cm32181", 0 },
{ }
@@ -370,7 +362,6 @@ static struct i2c_driver cm32181_driver = {
},
.id_table = cm32181_id,
.probe = cm32181_probe,
- .remove = cm32181_remove,
};
module_i2c_driver(cm32181_driver);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index ea08313af0d2..a2357921d761 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -165,7 +165,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
else
irq = gpio_to_irq(data->eoc_gpio);
- rc = request_irq(irq, ak8975_irq_handler,
+ rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&client->dev), data);
if (rc < 0) {
@@ -513,21 +513,21 @@ static int ak8975_probe(struct i2c_client *client,
/* We may not have a GPIO based IRQ to scan, that is fine, we will
poll if so */
if (gpio_is_valid(eoc_gpio)) {
- err = gpio_request_one(eoc_gpio, GPIOF_IN, "ak_8975");
+ err = devm_gpio_request_one(&client->dev, eoc_gpio,
+ GPIOF_IN, "ak_8975");
if (err < 0) {
dev_err(&client->dev,
"failed to request GPIO %d, error %d\n",
eoc_gpio, err);
- goto exit;
+ return err;
}
}
/* Register with IIO */
- indio_dev = iio_device_alloc(sizeof(*data));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto exit_gpio;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
@@ -542,17 +542,16 @@ static int ak8975_probe(struct i2c_client *client,
name = (char *) id->name;
} else if (ACPI_HANDLE(&client->dev))
name = ak8975_match_acpi_device(&client->dev, &data->chipset);
- else {
- err = -ENOSYS;
- goto exit_free_iio;
- }
+ else
+ return -ENOSYS;
+
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
/* Perform some basic start-of-day setup of the device. */
err = ak8975_setup(client);
if (err < 0) {
dev_err(&client->dev, "AK8975 initialization fails\n");
- goto exit_free_iio;
+ return err;
}
data->client = client;
@@ -564,37 +563,9 @@ static int ak8975_probe(struct i2c_client *client,
indio_dev->info = &ak8975_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = name;
- err = iio_device_register(indio_dev);
+ err = devm_iio_device_register(&client->dev, indio_dev);
if (err < 0)
- goto exit_free_iio;
-
- return 0;
-
-exit_free_iio:
- iio_device_free(indio_dev);
- if (data->eoc_irq)
- free_irq(data->eoc_irq, data);
-exit_gpio:
- if (gpio_is_valid(eoc_gpio))
- gpio_free(eoc_gpio);
-exit:
- return err;
-}
-
-static int ak8975_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ak8975_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- if (data->eoc_irq)
- free_irq(data->eoc_irq, data);
-
- if (gpio_is_valid(data->eoc_gpio))
- gpio_free(data->eoc_gpio);
-
- iio_device_free(indio_dev);
+ return err;
return 0;
}
@@ -621,7 +592,6 @@ static struct i2c_driver ak8975_driver = {
.acpi_match_table = ACPI_PTR(ak_acpi_match),
},
.probe = ak8975_probe,
- .remove = ak8975_remove,
.id_table = ak8975_id,
};
module_i2c_driver(ak8975_driver);
OpenPOWER on IntegriCloud