From f5ce4a7a9291d9e4b9aeaeb2bf8c33808de44989 Mon Sep 17 00:00:00 2001 From: Oskar Andero Date: Fri, 3 May 2013 10:58:00 +0100 Subject: [PATCH 1/9] iio: adc: add driver for MCP3204/08 12-bit ADC This adds support for Microchip's 12 bit AD converters MCP3204 and MCP3208. These chips communicates over SPI and supports single-ended and pseudo-differential configurations. Signed-off-by: Oskar Andero Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mcp320x.c | 257 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 drivers/iio/adc/mcp320x.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ab0767e6727e..93129ec4b649 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -133,6 +133,16 @@ config MAX1363 max11646, max11647) Provides direct access via sysfs and buffered data via the iio dev interface. +config MCP320X + tristate "Microchip Technology MCP3204/08" + depends on SPI + help + Say yes here to build support for Microchip Technology's MCP3204 or + MCP3208 analog to digital converter. + + This driver can also be built as a module. If so, the module will be + called mcp320x. + config TI_ADC081C tristate "Texas Instruments ADC081C021/027" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 0a825bed43f6..8f475d31fe4d 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c new file mode 100644 index 000000000000..ebc015922a79 --- /dev/null +++ b/drivers/iio/adc/mcp320x.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2013 Oskar Andero + * + * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips. + * Datasheet can be found here: + * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf + * + * 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 +#include +#include +#include +#include + +#define MCP_SINGLE_ENDED (1 << 3) +#define MCP_START_BIT (1 << 4) + +enum { + mcp3204, + mcp3208, +}; + +struct mcp320x { + struct spi_device *spi; + struct spi_message msg; + struct spi_transfer transfer[2]; + + u8 tx_buf; + u8 rx_buf[2]; + + struct regulator *reg; + struct mutex lock; +}; + +static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg) +{ + int ret; + + adc->tx_buf = msg; + ret = spi_sync(adc->spi, &adc->msg); + if (ret < 0) + return ret; + + return ((adc->rx_buf[0] & 0x3f) << 6) | + (adc->rx_buf[1] >> 2); +} + +static int mcp320x_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mcp320x *adc = iio_priv(indio_dev); + int ret = -EINVAL; + + mutex_lock(&adc->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (channel->differential) + ret = mcp320x_adc_conversion(adc, + MCP_START_BIT | channel->address); + else + ret = mcp320x_adc_conversion(adc, + MCP_START_BIT | MCP_SINGLE_ENDED | + channel->address); + if (ret < 0) + goto out; + + *val = ret; + ret = IIO_VAL_INT; + break; + + case IIO_CHAN_INFO_SCALE: + /* Digital output code = (4096 * Vin) / Vref */ + ret = regulator_get_voltage(adc->reg); + if (ret < 0) + goto out; + + *val = ret / 1000; + *val2 = 12; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + + default: + break; + } + +out: + mutex_unlock(&adc->lock); + + return ret; +} + +#define MCP320X_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (num), \ + .address = (num), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + } + +#define MCP320X_VOLTAGE_CHANNEL_DIFF(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (num * 2), \ + .channel2 = (num * 2 + 1), \ + .address = (num * 2), \ + .differential = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + } + +static const struct iio_chan_spec mcp3204_channels[] = { + MCP320X_VOLTAGE_CHANNEL(0), + MCP320X_VOLTAGE_CHANNEL(1), + MCP320X_VOLTAGE_CHANNEL(2), + MCP320X_VOLTAGE_CHANNEL(3), + MCP320X_VOLTAGE_CHANNEL_DIFF(0), + MCP320X_VOLTAGE_CHANNEL_DIFF(1), +}; + +static const struct iio_chan_spec mcp3208_channels[] = { + MCP320X_VOLTAGE_CHANNEL(0), + MCP320X_VOLTAGE_CHANNEL(1), + MCP320X_VOLTAGE_CHANNEL(2), + MCP320X_VOLTAGE_CHANNEL(3), + MCP320X_VOLTAGE_CHANNEL(4), + MCP320X_VOLTAGE_CHANNEL(5), + MCP320X_VOLTAGE_CHANNEL(6), + MCP320X_VOLTAGE_CHANNEL(7), + MCP320X_VOLTAGE_CHANNEL_DIFF(0), + MCP320X_VOLTAGE_CHANNEL_DIFF(1), + MCP320X_VOLTAGE_CHANNEL_DIFF(2), + MCP320X_VOLTAGE_CHANNEL_DIFF(3), +}; + +static const struct iio_info mcp320x_info = { + .read_raw = mcp320x_read_raw, + .driver_module = THIS_MODULE, +}; + +struct mcp3208_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +static const struct mcp3208_chip_info mcp3208_chip_infos[] = { + [mcp3204] = { + .channels = mcp3204_channels, + .num_channels = ARRAY_SIZE(mcp3204_channels) + }, + [mcp3208] = { + .channels = mcp3208_channels, + .num_channels = ARRAY_SIZE(mcp3208_channels) + }, +}; + +static int mcp320x_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct mcp320x *adc; + const struct mcp3208_chip_info *chip_info; + int ret; + + indio_dev = iio_device_alloc(sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp320x_info; + + chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data]; + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = chip_info->num_channels; + + adc->transfer[0].tx_buf = &adc->tx_buf; + adc->transfer[0].len = sizeof(adc->tx_buf); + adc->transfer[1].rx_buf = adc->rx_buf; + adc->transfer[1].len = sizeof(adc->rx_buf); + + spi_message_init_with_transfers(&adc->msg, adc->transfer, + ARRAY_SIZE(adc->transfer)); + + adc->reg = regulator_get(&spi->dev, "vref"); + if (IS_ERR(adc->reg)) { + ret = PTR_ERR(adc->reg); + goto iio_free; + } + + ret = regulator_enable(adc->reg); + if (ret < 0) + goto reg_free; + + mutex_init(&adc->lock); + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto reg_disable; + + return 0; + +reg_disable: + regulator_disable(adc->reg); +reg_free: + regulator_put(adc->reg); +iio_free: + iio_device_free(indio_dev); + + return ret; +} + +static int mcp320x_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct mcp320x *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(adc->reg); + regulator_put(adc->reg); + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id mcp320x_id[] = { + { "mcp3204", mcp3204 }, + { "mcp3208", mcp3208 }, + { } +}; +MODULE_DEVICE_TABLE(spi, mcp320x_id); + +static struct spi_driver mcp320x_driver = { + .driver = { + .name = "mcp320x", + .owner = THIS_MODULE, + }, + .probe = mcp320x_probe, + .remove = mcp320x_remove, + .id_table = mcp320x_id, +}; +module_spi_driver(mcp320x_driver); + +MODULE_AUTHOR("Oskar Andero "); +MODULE_DESCRIPTION("Microchip Technology MCP3204/08"); +MODULE_LICENSE("GPL v2"); From bec1889d24924f400249f5be8ee194728df5a191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 4 May 2013 14:19:00 +0100 Subject: [PATCH 2/9] iio: buffer: cleanup messages in iio_update_buffers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. make messages grepable (in one line) 2. include returned errno in them Signed-off-by: Michał Mirosław Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index aaadd32f9f0d..e73033f3839a 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -542,8 +542,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, ret = indio_dev->setup_ops->preenable(indio_dev); if (ret) { printk(KERN_ERR - "Buffer not started:" - "buffer preenable failed\n"); + "Buffer not started: buffer preenable failed (%d)\n", ret); goto error_remove_inserted; } } @@ -556,8 +555,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, ret = buffer->access->request_update(buffer); if (ret) { printk(KERN_INFO - "Buffer not started:" - "buffer parameter update failed\n"); + "Buffer not started: buffer parameter update failed (%d)\n", ret); goto error_run_postdisable; } } @@ -566,7 +564,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, ->update_scan_mode(indio_dev, indio_dev->active_scan_mask); if (ret < 0) { - printk(KERN_INFO "update scan mode failed\n"); + printk(KERN_INFO "Buffer not started: update scan mode failed (%d)\n", ret); goto error_run_postdisable; } } @@ -590,7 +588,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, ret = indio_dev->setup_ops->postenable(indio_dev); if (ret) { printk(KERN_INFO - "Buffer not started: postenable failed\n"); + "Buffer not started: postenable failed (%d)\n", ret); indio_dev->currentmode = INDIO_DIRECT_MODE; if (indio_dev->setup_ops->postdisable) indio_dev->setup_ops->postdisable(indio_dev); From f4914e5ef087961b3bf17cdf166e947f69cc9089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 4 May 2013 14:19:00 +0100 Subject: [PATCH 3/9] staging/iio/mxs-lradc: cleanup masklength MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We know the exact iio->masklength = LRADC_MAX_TOTAL_CHANS. Let's use it consistently. Signed-off-by: Michał Mirosław Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 2856b8fd44ad..03299eaa53cd 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -620,7 +620,7 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); unsigned int i, j = 0; - for_each_set_bit(i, iio->active_scan_mask, iio->masklength) { + for_each_set_bit(i, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); writel(chan_value, lradc->base + LRADC_CH(j)); lradc->buffer[j] &= LRADC_CH_VALUE_MASK; @@ -775,8 +775,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, const unsigned long *mask) { struct mxs_lradc *lradc = iio_priv(iio); - const int len = iio->masklength; - const int map_chans = bitmap_weight(mask, len); + const int map_chans = bitmap_weight(mask, LRADC_MAX_TOTAL_CHANS); int rsvd_chans = 0; unsigned long rsvd_mask = 0; @@ -793,7 +792,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, rsvd_chans++; /* Test for attempts to map channels with special mode of operation. */ - if (bitmap_intersects(mask, &rsvd_mask, len)) + if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS)) return false; /* Test for attempts to map more channels then available slots. */ @@ -969,6 +968,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) iio->modes = INDIO_DIRECT_MODE; iio->channels = mxs_lradc_chan_spec; iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec); + iio->masklength = LRADC_MAX_TOTAL_CHANS; ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, &mxs_lradc_trigger_handler, From e64e7d5c8c86ead27ed51a95687ba8327a9c4d2a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 14 Apr 2013 12:54:00 +0100 Subject: [PATCH 4/9] iio:trigger:sysfs Move out of staging. This simple driver is rather useful. No issues about its interface have been raised for some time hence the proposal to move it out of staging. Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 3 +++ drivers/iio/Makefile | 1 + drivers/iio/trigger/Kconfig | 17 +++++++++++++++++ drivers/iio/trigger/Makefile | 5 +++++ .../{staging => }/iio/trigger/iio-trig-sysfs.c | 0 drivers/staging/iio/trigger/Kconfig | 11 ----------- drivers/staging/iio/trigger/Makefile | 1 - 7 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 drivers/iio/trigger/Kconfig create mode 100644 drivers/iio/trigger/Makefile rename drivers/{staging => }/iio/trigger/iio-trig-sysfs.c (100%) diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index b2f963be3993..daa3dddbc77f 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -70,5 +70,8 @@ source "drivers/iio/gyro/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" +if IIO_TRIGGER + source "drivers/iio/trigger/Kconfig" +endif #IIO_TRIGGER endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index a0e8cdd67e4d..a349a9605d1f 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -21,3 +21,4 @@ obj-y += frequency/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += trigger/ diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig new file mode 100644 index 000000000000..a4e68db2f23f --- /dev/null +++ b/drivers/iio/trigger/Kconfig @@ -0,0 +1,17 @@ +# +# Industrial I/O standalone triggers +# +menu "Triggers - standalone" + +config IIO_SYSFS_TRIGGER + tristate "SYSFS trigger" + depends on SYSFS + select IRQ_WORK + help + Provides support for using SYSFS entry as IIO triggers. + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called iio-trig-sysfs. + +endmenu diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile new file mode 100644 index 000000000000..e0b21831072f --- /dev/null +++ b/drivers/iio/trigger/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for triggers not associated with iio-devices +# + +obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c similarity index 100% rename from drivers/staging/iio/trigger/iio-trig-sysfs.c rename to drivers/iio/trigger/iio-trig-sysfs.c diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index 1a051da62505..ae9fcd3382ea 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig @@ -18,17 +18,6 @@ config IIO_GPIO_TRIGGER help Provides support for using GPIO pins as IIO triggers. -config IIO_SYSFS_TRIGGER - tristate "SYSFS trigger" - depends on SYSFS - select IRQ_WORK - help - Provides support for using SYSFS entry as IIO triggers. - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called iio-trig-sysfs. - config IIO_BFIN_TMR_TRIGGER tristate "Blackfin TIMER trigger" depends on BLACKFIN diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile index b088b57da335..8a5304153b5b 100644 --- a/drivers/staging/iio/trigger/Makefile +++ b/drivers/staging/iio/trigger/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o -obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o From f4b7f751c6fd2bd7e6d3a83385ee292c39995bdb Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Tue, 7 May 2013 11:41:00 +0100 Subject: [PATCH 5/9] iio:ak8975 Add support for gpios DT property Add support for parsing 'gpios' property when initializing from oftree. This patch adds also the binding documentation file. Signed-off-by: Jacek Anaszewski Signed-off-by: Kyungmin Park Signed-off-by: Jonathan Cameron --- .../bindings/iio/magnetometer/ak8975.txt | 18 ++++++++++++++++++ drivers/iio/magnetometer/ak8975.c | 12 +++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/ak8975.txt diff --git a/Documentation/devicetree/bindings/iio/magnetometer/ak8975.txt b/Documentation/devicetree/bindings/iio/magnetometer/ak8975.txt new file mode 100644 index 000000000000..011679f1a425 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/ak8975.txt @@ -0,0 +1,18 @@ +* AsahiKASEI AK8975 magnetometer sensor + +Required properties: + + - compatible : should be "asahi-kasei,ak8975" + - reg : the I2C address of the magnetometer + +Optional properties: + + - gpios : should be device tree identifier of the magnetometer DRDY pin + +Example: + +ak8975@0c { + compatible = "asahi-kasei,ak8975"; + reg = <0x0c>; + gpios = <&gpj0 7 0>; +}; diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index af6c320a534e..d75cc23e8ae7 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -384,10 +385,15 @@ static int ak8975_probe(struct i2c_client *client, int err; /* Grab and set up the supplied GPIO. */ - if (client->dev.platform_data == NULL) - eoc_gpio = -1; - else + if (client->dev.platform_data) eoc_gpio = *(int *)(client->dev.platform_data); + else if (client->dev.of_node) + eoc_gpio = of_get_gpio(client->dev.of_node, 0); + else + eoc_gpio = -1; + + if (eoc_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; /* We may not have a GPIO based IRQ to scan, that is fine, we will poll if so */ From 94a6d5cf7caa5003e3b4d0c61a047329f26092f3 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Tue, 7 May 2013 11:41:00 +0100 Subject: [PATCH 6/9] iio:ak8975 Implement data ready interrupt handling Implement "data ready" interrupt handling in addition to the two existing read modes - DRDY GPIO polling and ST1 register DRDY bit polling. Signed-off-by: Jacek Anaszewski Signed-off-by: Kyungmin Park Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 91 ++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d75cc23e8ae7..7105f22d6cd7 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -24,10 +24,11 @@ #include #include #include +#include #include #include #include - +#include #include #include @@ -83,6 +84,7 @@ */ #define AK8975_MAX_CONVERSION_TIMEOUT 500 #define AK8975_CONVERSION_DONE_POLL_TIME 10 +#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) /* * Per-instance context data for the device. @@ -95,6 +97,9 @@ struct ak8975_data { long raw_to_gauss[3]; u8 reg_cache[AK8975_MAX_REGS]; int eoc_gpio; + int eoc_irq; + wait_queue_head_t data_ready_queue; + unsigned long flags; }; static const int ak8975_index_to_reg[] = { @@ -123,6 +128,51 @@ static int ak8975_write_data(struct i2c_client *client, return 0; } +/* + * Handle data ready irq + */ +static irqreturn_t ak8975_irq_handler(int irq, void *data) +{ + struct ak8975_data *ak8975 = data; + + set_bit(0, &ak8975->flags); + wake_up(&ak8975->data_ready_queue); + + return IRQ_HANDLED; +} + +/* + * Install data ready interrupt handler + */ +static int ak8975_setup_irq(struct ak8975_data *data) +{ + struct i2c_client *client = data->client; + int rc; + int irq; + + if (client->irq) + irq = client->irq; + else + irq = gpio_to_irq(data->eoc_gpio); + + rc = request_irq(irq, ak8975_irq_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(&client->dev), data); + if (rc < 0) { + dev_err(&client->dev, + "irq %d request failed, (gpio %d): %d\n", + irq, data->eoc_gpio, rc); + return rc; + } + + init_waitqueue_head(&data->data_ready_queue); + clear_bit(0, &data->flags); + data->eoc_irq = irq; + + return rc; +} + + /* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. @@ -171,6 +221,16 @@ static int ak8975_setup(struct i2c_client *client) AK8975_REG_CNTL_MODE_POWER_DOWN, AK8975_REG_CNTL_MODE_MASK, AK8975_REG_CNTL_MODE_SHIFT); + + if (data->eoc_gpio > 0 || client->irq) { + ret = ak8975_setup_irq(data); + if (ret < 0) { + dev_err(&client->dev, + "Error setting data ready interrupt\n"); + return ret; + } + } + if (ret < 0) { dev_err(&client->dev, "Error in setting power-down mode\n"); return ret; @@ -267,9 +327,23 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) dev_err(&client->dev, "Conversion timeout happened\n"); return -EINVAL; } + return read_status; } +/* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */ +static int wait_conversion_complete_interrupt(struct ak8975_data *data) +{ + int ret; + + ret = wait_event_timeout(data->data_ready_queue, + test_bit(0, &data->flags), + AK8975_DATA_READY_TIMEOUT); + clear_bit(0, &data->flags); + + return ret > 0 ? 0 : -ETIME; +} + /* * Emits the raw flux value for the x, y, or z axis. */ @@ -295,13 +369,16 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) } /* Wait for the conversion to complete. */ - if (gpio_is_valid(data->eoc_gpio)) + if (data->eoc_irq) + ret = wait_conversion_complete_interrupt(data); + else if (gpio_is_valid(data->eoc_gpio)) ret = wait_conversion_complete_gpio(data); else ret = wait_conversion_complete_polled(data); if (ret < 0) goto exit; + /* This will be executed only for non-interrupt based waiting case */ if (ret & AK8975_REG_ST1_DRDY_MASK) { ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2); if (ret < 0) { @@ -415,6 +492,11 @@ static int ak8975_probe(struct i2c_client *client, } data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); + + data->client = client; + data->eoc_gpio = eoc_gpio; + data->eoc_irq = 0; + /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); if (err < 0) { @@ -439,6 +521,8 @@ static int ak8975_probe(struct i2c_client *client, 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); @@ -453,6 +537,9 @@ static int ak8975_remove(struct i2c_client *client) 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); From 00a8d4234cd520fa7735a4421065ab6649d202ad Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 14 May 2013 10:05:00 +0100 Subject: [PATCH 7/9] iio: STMicroelectronics: remove three useless selects Drivers for STMicroelectronics accelerometers, gyroscopes, and magnetometers were added in v3.9. They all have a (similar) select statement in their Kconfig files for a non-existant Kconfig symbol. These select statements can safely be removed. Signed-off-by: Paul Bolle Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 1 - drivers/iio/gyro/Kconfig | 1 - drivers/iio/magnetometer/Kconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index bb594963f91e..719d83fe51dd 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -28,7 +28,6 @@ config IIO_ST_ACCEL_3AXIS select IIO_ST_ACCEL_I2C_3AXIS if (I2C) select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - select IIO_ST_ACCEL_BUFFER if (IIO_TRIGGERED_BUFFER) help Say yes here to build support for STMicroelectronics accelerometers: LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 6be4628faffe..b8daf1b2ea06 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -47,7 +47,6 @@ config IIO_ST_GYRO_3AXIS select IIO_ST_GYRO_I2C_3AXIS if (I2C) select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - select IIO_ST_GYRO_BUFFER if (IIO_TRIGGERED_BUFFER) help Say yes here to build support for STMicroelectronics gyroscopes: L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330. diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index bd1cfb666695..c332b0ae4a3b 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -32,7 +32,6 @@ config IIO_ST_MAGN_3AXIS select IIO_ST_MAGN_I2C_3AXIS if (I2C) select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - select IIO_ST_MAGN_BUFFER if (IIO_TRIGGERED_BUFFER) help Say yes here to build support for STMicroelectronics magnetometers: LSM303DLHC, LSM303DLM, LIS3MDL. From 39441078f76cf6733364f16e5c5b645c83de3c6e Mon Sep 17 00:00:00 2001 From: Alexandre Relange Date: Thu, 16 May 2013 14:54:00 +0100 Subject: [PATCH 8/9] iio: Correct HID light sensor name in comments The original driver was pasted from accelerometer driver, but the name of the ID was not changed. This patch fixes this comment. Signed-off-by: Alexandre Relange Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 80d68ff02d29..cdc2cad0f01b 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -31,7 +31,7 @@ #include "../common/hid-sensors/hid-sensor-trigger.h" /*Format: HID-SENSOR-usage_id_in_hex*/ -/*Usage ID from spec for Accelerometer-3D: 0x200041*/ +/*Usage ID from spec for Ambiant-Light: 0x200041*/ #define DRIVER_NAME "HID-SENSOR-200041" #define CHANNEL_SCAN_INDEX_ILLUM 0 From c619653d77a5d59abe9166da57f3686b7f067745 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 07:23:00 +0100 Subject: [PATCH 9/9] adc: exynos_adc: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. Signed-off-by: Sachin Kamat Signed-off-by: Jonathan Cameron --- drivers/iio/adc/exynos_adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 9f3a8ef1fb3e..22d034a55a62 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -270,16 +270,16 @@ static int exynos_adc_probe(struct platform_device *pdev) info = iio_priv(indio_dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_request_and_ioremap(&pdev->dev, mem); - if (!info->regs) { - ret = -ENOMEM; + info->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->regs)) { + ret = PTR_ERR(info->regs); goto err_iio; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - info->enable_reg = devm_request_and_ioremap(&pdev->dev, mem); - if (!info->enable_reg) { - ret = -ENOMEM; + info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->enable_reg)) { + ret = PTR_ERR(info->enable_reg); goto err_iio; }