Signed-off-by: Jacopo Mondi <jacopo@xxxxxxxxxx>
---
drivers/iio/adc/Kconfig | 9 +++
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/max11100.c | 165 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 175 insertions(+)
create mode 100644 drivers/iio/adc/max11100.c
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 99c0514..e2f3340 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -285,6 +285,15 @@ config MAX1027
To compile this driver as a module, choose M here: the module will be
called max1027.
+config MAX11100
+ tristate "Maxim max11100 ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for Maxim 11100 SPI ADC
Maxim max11100
+
+ To compile this driver as a module, choose M here: the module will be
+ called max11100.
+
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 7a40c04..1463044 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_MAX1027) += max1027.o
+obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
new file mode 100644
index 0000000..fbce287
--- /dev/null
+++ b/drivers/iio/adc/max11100.c
@@ -0,0 +1,165 @@
+/*
+ * iio/adc/max11100.c
+ * Maxim MAX11100 ADC Driver with IIO interface
MAX11100 or max11100
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016 Jacopo Mondi
+ *
+ * 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.
+ */
+#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>
+
+struct max11100_state {
+ const struct max11100_chip_desc *desc;
+ struct spi_device *spi;
+ struct mutex lock;
+};
+
+static struct iio_chan_spec max11100_channels[] = {
+ { /* [0] */
+ .type = IIO_VOLTAGE,
+ .channel = 0,
not indexed, so channel = 0 not needed
+ .address = 0,
address not needed (and no need to initialize to 0 anyway)
+ .scan_index = 0,
scan_index and scan_type not needed since no buffered support (yet); add
this when needed
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 24,
+ .shift = 8,
+ .repeat = 1,
+ .endianness = IIO_BE,
+ },
+ .output = 1,
no, ADC is typically not an output channel
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+};
+
+static const unsigned long max11100_scan_masks[] = {
scan_masks not needed since no buffered support
+ 0xffff,
+};
+
+static struct max11100_chip_desc {
+ uint32_t num_chan;
why not just unsigned?
+ const unsigned long *scanmasks;
not needed (yet)
+ const struct iio_chan_spec *channels;
+} max11100_desc = {
+ .num_chan = 1,
ARRAY_SIZE(max11100_channels)
+ .scanmasks = max11100_scan_masks,
+ .channels = max11100_channels,
+};
+
+static int max11100_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+ struct max11100_state *state = iio_priv(indio_dev);
+ uint8_t buffer[3] = { 0, 0, 0 };
no need to initialize buffer; consider alignment requirements for SPI
+
+ mutex_lock(&state->lock);
what is the mutex protecting?
must the spi_read() by protected? then the unlock can be placed right
after the call...
+
+ ret = spi_read(state->spi, (void *) buffer, 3);
sizeof(buffer)
+ if (ret) {
+ dev_err(&indio_dev->dev, "SPI transfer failed\n");
mutex_unlock()!?
+ return ret;
+ }
+
+ dev_dbg(&indio_dev->dev, "ADC output values: " \
+ "[0]: 0x%2x [1]: 0x%2x [2]: 0x%2x\n",
probably 0x%02x if really needed
+ buffer[0], buffer[1], buffer[2]);
+
+ /* the first 8 bits sent out from ADC must be 0s */
+ if (buffer[0]) {
+ dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
mutex_unlock()!?
+ return -EINVAL;
+ }
+
+ *val = (buffer[1] << 8) | buffer[2];
+ mutex_unlock(&state->lock);
+
shouldn't this return IIO_VAL_INT?
+ return 0;
+}
+
+static const struct iio_info max11100_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = max11100_read_raw,
+};
+
+static int max11100_probe(struct spi_device *spi)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct max11100_state *state;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (!indio_dev) {
+ pr_err("Can't allocate iio device\n");
error message really needed?
+ return -ENOMEM;
+ }
+ dev_dbg(&indio_dev->dev, "probe max11100 IIO SPI\n");
message really needed?
+
+ spi_set_drvdata(spi, indio_dev);
+
+ state = iio_priv(indio_dev);
+ state->spi = spi;
+ state->desc = &max11100_desc;
+
+ mutex_init(&state->lock);
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->dev.of_node = spi->dev.of_node;
+ indio_dev->info = &max11100_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = state->desc->channels;
+ indio_dev->num_channels = state->desc->num_chan;
+ indio_dev->available_scan_masks = state->desc->scanmasks;
+
+ ret = iio_device_register(indio_dev);
could use devm_ variant...
+ if (ret) {
+ dev_err(&indio_dev->dev, "Failed to register iio device\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max11100_remove(struct spi_device *spi)
function not needed if using devm_iio_device_register()
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ dev_dbg(&indio_dev->dev, "remove max11100 IIO SPI\n");
+
+ iio_device_unregister(indio_dev);
+
+ return 0;
+}
+
+static const struct of_device_id max11100_ids[] = {
+ {.compatible = "maxim,max11100"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, max11100_ids);
+
+static struct spi_driver max11100_driver = {
+ .driver = {
+ .name = "max11100",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max11100_ids),
+ },
+ .probe = max11100_probe,
+ .remove = max11100_remove,
+};
+
+module_spi_driver(max11100_driver);
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo@xxxxxxxxxx>");
+MODULE_DESCRIPTION("Maxim MAX11100 ADC Driver");
+MODULE_LICENSE("GPL v2");