From 598db5816664472e1649ef94b0ba4c5cc1b9f3b4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 13 Mar 2014 16:46:00 +0000 Subject: iio: force snprintf for PAGE_SIZE bufs This is a tiny preventative measure to make sure we can't write beyond PAGE_SIZE on the buffers being used in sysfs for iio. There is currently no way for this to happen, but the change makes this code more robust for the future. Signed-off-by: Kees Cook Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index ede16aec..1375921 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -340,7 +340,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev, else if (i >= e->num_items) return -EINVAL; - return sprintf(buf, "%s\n", e->items[i]); + return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]); } EXPORT_SYMBOL_GPL(iio_enum_read); @@ -820,7 +820,7 @@ static ssize_t iio_show_dev_name(struct device *dev, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); - return sprintf(buf, "%s\n", indio_dev->name); + return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name); } static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); -- cgit v1.1 From 24ddb0e4bba4e98d3f3a783846789520e796b164 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 3 Dec 2014 12:53:00 +0000 Subject: iio: Add AS3935 lightning sensor support AS3935 chipset can detect lightning strikes and reports those back as events and the estimated distance to the storm. Signed-off-by: Matt Ranostay Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/proximity/Kconfig | 19 ++ drivers/iio/proximity/Makefile | 6 + drivers/iio/proximity/as3935.c | 456 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 483 insertions(+) create mode 100644 drivers/iio/proximity/Kconfig create mode 100644 drivers/iio/proximity/Makefile create mode 100644 drivers/iio/proximity/as3935.c (limited to 'drivers') diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 5dd0e12..743485e4 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -74,6 +74,7 @@ if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER source "drivers/iio/pressure/Kconfig" +source "drivers/iio/proximity/Kconfig" source "drivers/iio/temperature/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 887d3909..698afc2 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -24,5 +24,6 @@ obj-y += light/ obj-y += magnetometer/ obj-y += orientation/ obj-y += pressure/ +obj-y += proximity/ obj-y += temperature/ obj-y += trigger/ diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig new file mode 100644 index 0000000..0c8cdf5 --- /dev/null +++ b/drivers/iio/proximity/Kconfig @@ -0,0 +1,19 @@ +# +# Proximity sensors +# + +menu "Lightning sensors" + +config AS3935 + tristate "AS3935 Franklin lightning sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + depends on SPI + help + Say Y here to build SPI interface support for the Austrian + Microsystems AS3935 lightning detection sensor. + + To compile this driver as a module, choose M here: the + module will be called as3935 + +endmenu diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile new file mode 100644 index 0000000..743adee --- /dev/null +++ b/drivers/iio/proximity/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for IIO proximity sensors +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AS3935) += as3935.o diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c new file mode 100644 index 0000000..bf677bf --- /dev/null +++ b/drivers/iio/proximity/as3935.c @@ -0,0 +1,456 @@ +/* + * as3935.c - Support for AS3935 Franklin lightning sensor + * + * Copyright (C) 2014 Matt Ranostay + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AS3935_AFE_GAIN 0x00 +#define AS3935_AFE_MASK 0x3F +#define AS3935_AFE_GAIN_MAX 0x1F +#define AS3935_AFE_PWR_BIT BIT(0) + +#define AS3935_INT 0x03 +#define AS3935_INT_MASK 0x07 +#define AS3935_EVENT_INT BIT(3) +#define AS3935_NOISE_INT BIT(1) + +#define AS3935_DATA 0x07 +#define AS3935_DATA_MASK 0x3F + +#define AS3935_TUNE_CAP 0x08 +#define AS3935_CALIBRATE 0x3D + +#define AS3935_WRITE_DATA BIT(15) +#define AS3935_READ_DATA BIT(14) +#define AS3935_ADDRESS(x) ((x) << 8) + +#define MAX_PF_CAP 120 +#define TUNE_CAP_DIV 8 + +struct as3935_state { + struct spi_device *spi; + struct iio_trigger *trig; + struct mutex lock; + struct delayed_work work; + + u32 tune_cap; + u8 buf[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec as3935_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 6, + .storagebits = 8, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int as3935_read(struct as3935_state *st, unsigned int reg, int *val) +{ + u8 cmd; + int ret; + + cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8; + ret = spi_w8r8(st->spi, cmd); + if (ret < 0) + return ret; + *val = ret; + + return 0; +}; + +static int as3935_write(struct as3935_state *st, + unsigned int reg, + unsigned int val) +{ + u8 *buf = st->buf; + + buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8; + buf[1] = val; + + return spi_write(st->spi, buf, 2); +}; + +static ssize_t as3935_sensor_sensitivity_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct as3935_state *st = iio_priv(dev_to_iio_dev(dev)); + int val, ret; + + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + return ret; + val = (val & AS3935_AFE_MASK) >> 1; + + return sprintf(buf, "%d\n", val); +}; + +static ssize_t as3935_sensor_sensitivity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct as3935_state *st = iio_priv(dev_to_iio_dev(dev)); + unsigned long val; + int ret; + + ret = kstrtoul((const char *) buf, 10, &val); + if (ret) + return -EINVAL; + + if (val > AS3935_AFE_GAIN_MAX) + return -EINVAL; + + as3935_write(st, AS3935_AFE_GAIN, val << 1); + + return len; +}; + +static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR, + as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0); + + +static struct attribute *as3935_attributes[] = { + &iio_dev_attr_sensor_sensitivity.dev_attr.attr, + NULL, +}; + +static struct attribute_group as3935_attribute_group = { + .attrs = as3935_attributes, +}; + +static int as3935_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct as3935_state *st = iio_priv(indio_dev); + int ret; + + + switch (m) { + case IIO_CHAN_INFO_PROCESSED: + case IIO_CHAN_INFO_RAW: + *val2 = 0; + ret = as3935_read(st, AS3935_DATA, val); + if (ret) + return ret; + + if (m == IIO_CHAN_INFO_RAW) + return IIO_VAL_INT; + + /* storm out of range */ + if (*val == AS3935_DATA_MASK) + return -EINVAL; + *val *= 1000; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static const struct iio_info as3935_info = { + .driver_module = THIS_MODULE, + .attrs = &as3935_attribute_group, + .read_raw = &as3935_read_raw, +}; + +static irqreturn_t as3935_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + ret = as3935_read(st, AS3935_DATA, &val); + if (ret) + goto err_read; + val &= AS3935_DATA_MASK; + val *= 1000; + + iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp); +err_read: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +}; + +static const struct iio_trigger_ops iio_interrupt_trigger_ops = { + .owner = THIS_MODULE, +}; + +static void as3935_event_work(struct work_struct *work) +{ + struct as3935_state *st; + int val; + + st = container_of(work, struct as3935_state, work.work); + + as3935_read(st, AS3935_INT, &val); + val &= AS3935_INT_MASK; + + switch (val) { + case AS3935_EVENT_INT: + iio_trigger_poll(st->trig, iio_get_time_ns()); + break; + case AS3935_NOISE_INT: + dev_warn(&st->spi->dev, "noise level is too high"); + break; + } +}; + +static irqreturn_t as3935_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct as3935_state *st = iio_priv(indio_dev); + + /* + * Delay work for >2 milliseconds after an interrupt to allow + * estimated distance to recalculated. + */ + + schedule_delayed_work(&st->work, msecs_to_jiffies(3)); + + return IRQ_HANDLED; +} + +static void calibrate_as3935(struct as3935_state *st) +{ + mutex_lock(&st->lock); + + /* mask disturber interrupt bit */ + as3935_write(st, AS3935_INT, BIT(5)); + + as3935_write(st, AS3935_CALIBRATE, 0x96); + as3935_write(st, AS3935_TUNE_CAP, + BIT(5) | (st->tune_cap / TUNE_CAP_DIV)); + + mdelay(2); + as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV)); + + mutex_unlock(&st->lock); +} + +#ifdef CONFIG_PM_SLEEP +static int as3935_suspend(struct spi_device *spi, pm_message_t msg) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + mutex_lock(&st->lock); + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + goto err_suspend; + val |= AS3935_AFE_PWR_BIT; + + ret = as3935_write(st, AS3935_AFE_GAIN, val); + +err_suspend: + mutex_unlock(&st->lock); + + return ret; +} + +static int as3935_resume(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + int val, ret; + + mutex_lock(&st->lock); + ret = as3935_read(st, AS3935_AFE_GAIN, &val); + if (ret) + goto err_resume; + val &= ~AS3935_AFE_PWR_BIT; + ret = as3935_write(st, AS3935_AFE_GAIN, val); + +err_resume: + mutex_unlock(&st->lock); + + return ret; +} +#else +#define as3935_suspend NULL +#define as3935_resume NULL +#endif + +static int as3935_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct iio_trigger *trig; + struct as3935_state *st; + struct device_node *np = spi->dev.of_node; + int ret; + + /* Be sure lightning event interrupt is specified */ + if (!spi->irq) { + dev_err(&spi->dev, "unable to get event interrupt\n"); + return -EINVAL; + } + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->tune_cap = 0; + + spi_set_drvdata(spi, indio_dev); + mutex_init(&st->lock); + INIT_DELAYED_WORK(&st->work, as3935_event_work); + + ret = of_property_read_u32(np, + "ams,tuning-capacitor-pf", &st->tune_cap); + if (ret) { + st->tune_cap = 0; + dev_warn(&spi->dev, + "no tuning-capacitor-pf set, defaulting to %d", + st->tune_cap); + } + + if (st->tune_cap > MAX_PF_CAP) { + dev_err(&spi->dev, + "wrong tuning-capacitor-pf setting of %d\n", + st->tune_cap); + return -EINVAL; + } + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->channels = as3935_channels; + indio_dev->num_channels = ARRAY_SIZE(as3935_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &as3935_info; + + trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + + if (!trig) + return -ENOMEM; + + st->trig = trig; + trig->dev.parent = indio_dev->dev.parent; + iio_trigger_set_drvdata(trig, indio_dev); + trig->ops = &iio_interrupt_trigger_ops; + + ret = iio_trigger_register(trig); + if (ret) { + dev_err(&spi->dev, "failed to register trigger\n"); + return ret; + } + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &as3935_trigger_handler, NULL); + + if (ret) { + dev_err(&spi->dev, "cannot setup iio trigger\n"); + goto unregister_trigger; + } + + calibrate_as3935(st); + + ret = devm_request_irq(&spi->dev, spi->irq, + &as3935_interrupt_handler, + IRQF_TRIGGER_RISING, + dev_name(&spi->dev), + indio_dev); + + if (ret) { + dev_err(&spi->dev, "unable to request irq\n"); + goto unregister_buffer; + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&spi->dev, "unable to register device\n"); + goto unregister_buffer; + } + return 0; + +unregister_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +unregister_trigger: + iio_trigger_unregister(st->trig); + + return ret; +}; + +static int as3935_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct as3935_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(st->trig); + + return 0; +}; + +static const struct spi_device_id as3935_id[] = { + {"as3935", 0}, + {}, +}; +MODULE_DEVICE_TABLE(spi, as3935_id); + +static struct spi_driver as3935_driver = { + .driver = { + .name = "as3935", + .owner = THIS_MODULE, + }, + .probe = as3935_probe, + .remove = as3935_remove, + .id_table = as3935_id, + .suspend = as3935_suspend, + .resume = as3935_resume, +}; +module_spi_driver(as3935_driver); + +MODULE_AUTHOR("Matt Ranostay "); +MODULE_DESCRIPTION("AS3935 lightning sensor"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:as3935"); -- cgit v1.1 From 476d4af22cec8a9ebc90137712e5ab7070b7379d Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 3 Oct 2014 17:25:00 +0100 Subject: iio: inkern: add iio_read_channel_average_raw Add iio_read_channel_average_raw to support reading averaged raw values in consumer drivers. Signed-off-by: Sebastian Reichel Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 0cf5f8e..adeba5a 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -443,6 +443,24 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_read_channel_raw); +int iio_read_channel_average_raw(struct iio_channel *chan, int *val) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); + static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { -- cgit v1.1 From 396590b3bc919800d40464559f2a9c16938a193f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 3 Oct 2014 10:31:00 +0100 Subject: staging:iio:ad799x: Move ring functions to the main file The ad799x_ring.c file is pretty much only one function these days. No need to keep it in a separate file. Since there is then only one user of the header left also move everything from the header to the main file. Signed-off-by: Lars-Peter Clausen Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/Kconfig | 13 +-- drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/ad799x.h | 121 ---------------------------- drivers/staging/iio/adc/ad799x_core.c | 145 +++++++++++++++++++++++++++++++++- drivers/staging/iio/adc/ad799x_ring.c | 84 -------------------- 5 files changed, 143 insertions(+), 221 deletions(-) delete mode 100644 drivers/staging/iio/adc/ad799x.h delete mode 100644 drivers/staging/iio/adc/ad799x_ring.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 3633298..ed23cce 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -40,23 +40,14 @@ config AD7606_IFACE_SPI config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C - select IIO_TRIGGER if IIO_BUFFER - select AD799X_RING_BUFFER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for Analog Devices: ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 i2c analog to digital converters (ADC). Provides direct access via sysfs. -config AD799X_RING_BUFFER - bool "Analog Devices AD799x: use ring buffer" - depends on AD799X - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to include ring buffer support in the AD799X - ADC driver. - config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 3e9fb14..b2d35f8 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -9,7 +9,6 @@ ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o ad799x-y := ad799x_core.o -ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AD7291) += ad7291.o diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h deleted file mode 100644 index fc8c852..0000000 --- a/drivers/staging/iio/adc/ad799x.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. - * Copyright (C) 2008-2010 Jonathan Cameron - * - * 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. - * - * ad799x.h - */ - -#ifndef _AD799X_H_ -#define _AD799X_H_ - -#define AD799X_CHANNEL_SHIFT 4 -#define AD799X_STORAGEBITS 16 -/* - * AD7991, AD7995 and AD7999 defines - */ - -#define AD7991_REF_SEL 0x08 -#define AD7991_FLTR 0x04 -#define AD7991_BIT_TRIAL_DELAY 0x02 -#define AD7991_SAMPLE_DELAY 0x01 - -/* - * AD7992, AD7993, AD7994, AD7997 and AD7998 defines - */ - -#define AD7998_FLTR 0x08 -#define AD7998_ALERT_EN 0x04 -#define AD7998_BUSY_ALERT 0x02 -#define AD7998_BUSY_ALERT_POL 0x01 - -#define AD7998_CONV_RES_REG 0x0 -#define AD7998_ALERT_STAT_REG 0x1 -#define AD7998_CONF_REG 0x2 -#define AD7998_CYCLE_TMR_REG 0x3 - -#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) -#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) -#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) - -#define AD7998_CYC_MASK 0x7 -#define AD7998_CYC_DIS 0x0 -#define AD7998_CYC_TCONF_32 0x1 -#define AD7998_CYC_TCONF_64 0x2 -#define AD7998_CYC_TCONF_128 0x3 -#define AD7998_CYC_TCONF_256 0x4 -#define AD7998_CYC_TCONF_512 0x5 -#define AD7998_CYC_TCONF_1024 0x6 -#define AD7998_CYC_TCONF_2048 0x7 - -#define AD7998_ALERT_STAT_CLEAR 0xFF - -/* - * AD7997 and AD7997 defines - */ - -#define AD7997_8_READ_SINGLE 0x80 -#define AD7997_8_READ_SEQUENCE 0x70 -/* TODO: move this into a common header */ -#define RES_MASK(bits) ((1 << (bits)) - 1) - -enum { - ad7991, - ad7995, - ad7999, - ad7992, - ad7993, - ad7994, - ad7997, - ad7998 -}; - -struct ad799x_state; - -/** - * struct ad799x_chip_info - chip specifc information - * @channel: channel specification - * @num_channels: number of channels - * @monitor_mode: whether the chip supports monitor interrupts - * @default_config: device default configuration - * @event_attrs: pointer to the monitor event attribute group - */ - -struct ad799x_chip_info { - struct iio_chan_spec channel[9]; - int num_channels; - u16 default_config; - const struct iio_info *info; -}; - -struct ad799x_state { - struct i2c_client *client; - const struct ad799x_chip_info *chip_info; - struct regulator *reg; - struct regulator *vref; - unsigned id; - u16 config; - - u8 *rx_buf; - unsigned int transfer_size; -}; - -#ifdef CONFIG_AD799X_RING_BUFFER -int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); -void ad799x_ring_cleanup(struct iio_dev *indio_dev); -#else /* CONFIG_AD799X_RING_BUFFER */ - -static inline int -ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev) -{ -} -#endif /* CONFIG_AD799X_RING_BUFFER */ -#endif /* _AD799X_H_ */ diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 979ec77..bcbf610 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -37,8 +37,144 @@ #include #include #include +#include +#include -#include "ad799x.h" +#define AD799X_CHANNEL_SHIFT 4 +#define AD799X_STORAGEBITS 16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR 0x08 +#define AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_ALERT 0x02 +#define AD7998_BUSY_ALERT_POL 0x01 + +#define AD7998_CONV_RES_REG 0x0 +#define AD7998_ALERT_STAT_REG 0x1 +#define AD7998_CONF_REG 0x2 +#define AD7998_CYCLE_TMR_REG 0x3 + +#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) +#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) +#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) + +#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_DIS 0x0 +#define AD7998_CYC_TCONF_32 0x1 +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCONF_128 0x3 +#define AD7998_CYC_TCONF_256 0x4 +#define AD7998_CYC_TCONF_512 0x5 +#define AD7998_CYC_TCONF_1024 0x6 +#define AD7998_CYC_TCONF_2048 0x7 + +#define AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 +/* TODO: move this into a common header */ +#define RES_MASK(bits) ((1 << (bits)) - 1) + +enum { + ad7991, + ad7995, + ad7999, + ad7992, + ad7993, + ad7994, + ad7997, + ad7998 +}; + +/** + * struct ad799x_chip_info - chip specifc information + * @channel: channel specification + * @num_channels: number of channels + * @monitor_mode: whether the chip supports monitor interrupts + * @default_config: device default configuration + * @event_attrs: pointer to the monitor event attribute group + */ +struct ad799x_chip_info { + struct iio_chan_spec channel[9]; + int num_channels; + u16 default_config; + const struct iio_info *info; +}; + +struct ad799x_state { + struct i2c_client *client; + const struct ad799x_chip_info *chip_info; + struct regulator *reg; + struct regulator *vref; + unsigned id; + u16 config; + + u8 *rx_buf; + unsigned int transfer_size; +}; + +/** + * ad799x_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad799x_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad799x_state *st = iio_priv(indio_dev); + int b_sent; + u8 cmd; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | + (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | + AD7998_CONV_RES_REG; + break; + case ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; + break; + default: + cmd = 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, + cmd, st->transfer_size, st->rx_buf); + if (b_sent < 0) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} /* * ad799x register access by I2C @@ -578,7 +714,8 @@ static int ad799x_probe(struct i2c_client *client, indio_dev->channels = st->chip_info->channel; indio_dev->num_channels = st->chip_info->num_channels; - ret = ad799x_register_ring_funcs_and_init(indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ad799x_trigger_handler, NULL); if (ret) goto error_disable_reg; @@ -601,7 +738,7 @@ static int ad799x_probe(struct i2c_client *client, return 0; error_cleanup_ring: - ad799x_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); error_disable_reg: if (!IS_ERR(st->vref)) regulator_disable(st->vref); @@ -618,7 +755,7 @@ static int ad799x_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - ad799x_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); if (!IS_ERR(st->vref)) regulator_disable(st->vref); if (!IS_ERR(st->reg)) diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c deleted file mode 100644 index 0ff6c03..0000000 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc. - * Copyright (C) 2008-2010 Jonathan Cameron - * - * 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. - * - * ad799x_ring.c - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "ad799x.h" - -/** - * ad799x_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ - -static irqreturn_t ad799x_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad799x_state *st = iio_priv(indio_dev); - int b_sent; - u8 cmd; - - switch (st->id) { - case ad7991: - case ad7995: - case ad7999: - cmd = st->config | - (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); - break; - case ad7992: - case ad7993: - case ad7994: - cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | - AD7998_CONV_RES_REG; - break; - case ad7997: - case ad7998: - cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; - break; - default: - cmd = 0; - } - - b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, st->transfer_size, st->rx_buf); - if (b_sent < 0) - goto out; - - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); -out: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, NULL, - &ad799x_trigger_handler, NULL); -} - -void ad799x_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} -- cgit v1.1 From bd75afaa314b2743c5379df3ccc84fab03126b71 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 3 Oct 2014 10:31:00 +0100 Subject: staging:iio: Move ad799x driver out of staging The driver is now at a reasonable quality level. Move it out of staging. Signed-off-by: Lars-Peter Clausen Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad799x.c | 794 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 11 - drivers/staging/iio/adc/Makefile | 3 - drivers/staging/iio/adc/ad799x_core.c | 794 ---------------------------------- 6 files changed, 806 insertions(+), 808 deletions(-) create mode 100644 drivers/iio/adc/ad799x.c delete mode 100644 drivers/staging/iio/adc/ad799x_core.c (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5553206..a036811 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -96,6 +96,17 @@ config AD7923 To compile this driver as a module, choose M here: the module will be called ad7923. +config AD799X + tristate "Analog Devices AD799x ADC driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices: + ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 + i2c analog to digital converters (ADC). Provides direct access + via sysfs. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 89f1216..1e2fc891 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o +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 diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c new file mode 100644 index 0000000..bcbf610 --- /dev/null +++ b/drivers/iio/adc/ad799x.c @@ -0,0 +1,794 @@ +/* + * iio/adc/ad799x.c + * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. + * + * based on iio/adc/max1363 + * Copyright (C) 2008-2010 Jonathan Cameron + * + * based on linux/drivers/i2c/chips/max123x + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * 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. + * + * ad799x.c + * + * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, + * ad7998 and similar chips. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define AD799X_CHANNEL_SHIFT 4 +#define AD799X_STORAGEBITS 16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR 0x08 +#define AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_ALERT 0x02 +#define AD7998_BUSY_ALERT_POL 0x01 + +#define AD7998_CONV_RES_REG 0x0 +#define AD7998_ALERT_STAT_REG 0x1 +#define AD7998_CONF_REG 0x2 +#define AD7998_CYCLE_TMR_REG 0x3 + +#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) +#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) +#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) + +#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_DIS 0x0 +#define AD7998_CYC_TCONF_32 0x1 +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCONF_128 0x3 +#define AD7998_CYC_TCONF_256 0x4 +#define AD7998_CYC_TCONF_512 0x5 +#define AD7998_CYC_TCONF_1024 0x6 +#define AD7998_CYC_TCONF_2048 0x7 + +#define AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 +/* TODO: move this into a common header */ +#define RES_MASK(bits) ((1 << (bits)) - 1) + +enum { + ad7991, + ad7995, + ad7999, + ad7992, + ad7993, + ad7994, + ad7997, + ad7998 +}; + +/** + * struct ad799x_chip_info - chip specifc information + * @channel: channel specification + * @num_channels: number of channels + * @monitor_mode: whether the chip supports monitor interrupts + * @default_config: device default configuration + * @event_attrs: pointer to the monitor event attribute group + */ +struct ad799x_chip_info { + struct iio_chan_spec channel[9]; + int num_channels; + u16 default_config; + const struct iio_info *info; +}; + +struct ad799x_state { + struct i2c_client *client; + const struct ad799x_chip_info *chip_info; + struct regulator *reg; + struct regulator *vref; + unsigned id; + u16 config; + + u8 *rx_buf; + unsigned int transfer_size; +}; + +/** + * ad799x_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad799x_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad799x_state *st = iio_priv(indio_dev); + int b_sent; + u8 cmd; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | + (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | + AD7998_CONV_RES_REG; + break; + case ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; + break; + default: + cmd = 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, + cmd, st->transfer_size, st->rx_buf); + if (b_sent < 0) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns()); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +/* + * ad799x register access by I2C + */ +static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_word_swapped(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = (u16)ret; + + return 0; +} + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = (u8)ret; + + return 0; +} + +static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_word_swapped(client, reg, data); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad799x_state *st = iio_priv(indio_dev); + + kfree(st->rx_buf); + st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); + if (!st->rx_buf) + return -ENOMEM; + + st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2; + + switch (st->id) { + case ad7997: + case ad7998: + return ad799x_i2c_write16(st, AD7998_CONF_REG, + st->config | (*scan_mask << AD799X_CHANNEL_SHIFT)); + default: + break; + } + + return 0; +} + +static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) +{ + u16 rxbuf; + u8 cmd; + int ret; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (1 << ch) << AD799X_CHANNEL_SHIFT; + break; + case ad7997: + case ad7998: + cmd = (ch << AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE; + break; + default: + return -EINVAL; + } + + ret = ad799x_i2c_read16(st, cmd, &rxbuf); + if (ret < 0) + return ret; + + return rxbuf; +} + +static int ad799x_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret; + struct ad799x_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) + ret = -EBUSY; + else + ret = ad799x_scan_direct(st, chan->scan_index); + mutex_unlock(&indio_dev->mlock); + + if (ret < 0) + return ret; + *val = (ret >> chan->scan_type.shift) & + RES_MASK(chan->scan_type.realbits); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(st->vref); + if (ret < 0) + return ret; + *val = ret / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + } + return -EINVAL; +} +static const unsigned int ad7998_frequencies[] = { + [AD7998_CYC_DIS] = 0, + [AD7998_CYC_TCONF_32] = 15625, + [AD7998_CYC_TCONF_64] = 7812, + [AD7998_CYC_TCONF_128] = 3906, + [AD7998_CYC_TCONF_512] = 976, + [AD7998_CYC_TCONF_1024] = 488, + [AD7998_CYC_TCONF_2048] = 244, +}; +static ssize_t ad799x_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad799x_state *st = iio_priv(indio_dev); + + int ret; + u8 val; + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + if (ret) + return ret; + + val &= AD7998_CYC_MASK; + + return sprintf(buf, "%u\n", ad7998_frequencies[val]); +} + +static ssize_t ad799x_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad799x_state *st = iio_priv(indio_dev); + + long val; + int ret, i; + u8 t; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); + if (ret) + goto error_ret_mutex; + /* Wipe the bits clean */ + t &= ~AD7998_CYC_MASK; + + for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) + if (val == ad7998_frequencies[i]) + break; + if (i == ARRAY_SIZE(ad7998_frequencies)) { + ret = -EINVAL; + goto error_ret_mutex; + } + t |= i; + ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + +error_ret_mutex: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static int ad799x_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + return 1; +} + +static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, + enum iio_event_direction dir, + enum iio_event_info info) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + if (dir == IIO_EV_DIR_FALLING) + return AD7998_DATALOW_REG(chan->channel); + else + return AD7998_DATAHIGH_REG(chan->channel); + case IIO_EV_INFO_HYSTERESIS: + return AD7998_HYST_REG(chan->channel); + default: + return -EINVAL; + } + + return 0; +} + +static int ad799x_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + int ret; + struct ad799x_state *st = iio_priv(indio_dev); + + mutex_lock(&indio_dev->mlock); + ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), + val); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad799x_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + int ret; + struct ad799x_state *st = iio_priv(indio_dev); + u16 valin; + + mutex_lock(&indio_dev->mlock); + ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), + &valin); + mutex_unlock(&indio_dev->mlock); + if (ret < 0) + return ret; + *val = valin; + + return IIO_VAL_INT; +} + +static irqreturn_t ad799x_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ad799x_state *st = iio_priv(private); + u8 status; + int i, ret; + + ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status); + if (ret) + goto done; + + if (!status) + goto done; + + ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); + + for (i = 0; i < 8; i++) { + if (status & (1 << i)) + iio_push_event(indio_dev, + i & 0x1 ? + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + (i >> 1), + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING) : + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + (i >> 1), + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + +done: + return IRQ_HANDLED; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ad799x_read_frequency, + ad799x_write_frequency); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); + +static struct attribute *ad799x_event_attributes[] = { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad799x_event_attrs_group = { + .attrs = ad799x_event_attributes, + .name = "events", +}; + +static const struct iio_info ad7991_info = { + .read_raw = &ad799x_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct iio_info ad7993_4_7_8_info = { + .read_raw = &ad799x_read_raw, + .event_attrs = &ad799x_event_attrs_group, + .read_event_config = &ad799x_read_event_config, + .read_event_value = &ad799x_read_event_value, + .write_event_value = &ad799x_write_event_value, + .driver_module = THIS_MODULE, + .update_scan_mode = ad7997_8_update_scan_mode, +}; + +static const struct iio_event_spec ad799x_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \ + .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), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_realbits), \ + .storagebits = 16, \ + .shift = 12 - (_realbits), \ + .endianness = IIO_BE, \ + }, \ + .event_spec = _ev_spec, \ + .num_event_specs = _num_ev_spec, \ +} + +#define AD799X_CHANNEL(_index, _realbits) \ + _AD799X_CHANNEL(_index, _realbits, NULL, 0) + +#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \ + _AD799X_CHANNEL(_index, _realbits, ad799x_events, \ + ARRAY_SIZE(ad799x_events)) + +static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { + [ad7991] = { + .channel = { + AD799X_CHANNEL(0, 12), + AD799X_CHANNEL(1, 12), + AD799X_CHANNEL(2, 12), + AD799X_CHANNEL(3, 12), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .num_channels = 5, + .info = &ad7991_info, + }, + [ad7995] = { + .channel = { + AD799X_CHANNEL(0, 10), + AD799X_CHANNEL(1, 10), + AD799X_CHANNEL(2, 10), + AD799X_CHANNEL(3, 10), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .num_channels = 5, + .info = &ad7991_info, + }, + [ad7999] = { + .channel = { + AD799X_CHANNEL(0, 8), + AD799X_CHANNEL(1, 8), + AD799X_CHANNEL(2, 8), + AD799X_CHANNEL(3, 8), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .num_channels = 5, + .info = &ad7991_info, + }, + [ad7992] = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + IIO_CHAN_SOFT_TIMESTAMP(3), + }, + .num_channels = 3, + .default_config = AD7998_ALERT_EN, + .info = &ad7993_4_7_8_info, + }, + [ad7993] = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .num_channels = 5, + .default_config = AD7998_ALERT_EN, + .info = &ad7993_4_7_8_info, + }, + [ad7994] = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), + IIO_CHAN_SOFT_TIMESTAMP(4), + }, + .num_channels = 5, + .default_config = AD7998_ALERT_EN, + .info = &ad7993_4_7_8_info, + }, + [ad7997] = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 10), + AD799X_CHANNEL_WITH_EVENTS(1, 10), + AD799X_CHANNEL_WITH_EVENTS(2, 10), + AD799X_CHANNEL_WITH_EVENTS(3, 10), + AD799X_CHANNEL(4, 10), + AD799X_CHANNEL(5, 10), + AD799X_CHANNEL(6, 10), + AD799X_CHANNEL(7, 10), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .num_channels = 9, + .default_config = AD7998_ALERT_EN, + .info = &ad7993_4_7_8_info, + }, + [ad7998] = { + .channel = { + AD799X_CHANNEL_WITH_EVENTS(0, 12), + AD799X_CHANNEL_WITH_EVENTS(1, 12), + AD799X_CHANNEL_WITH_EVENTS(2, 12), + AD799X_CHANNEL_WITH_EVENTS(3, 12), + AD799X_CHANNEL(4, 12), + AD799X_CHANNEL(5, 12), + AD799X_CHANNEL(6, 12), + AD799X_CHANNEL(7, 12), + IIO_CHAN_SOFT_TIMESTAMP(8), + }, + .num_channels = 9, + .default_config = AD7998_ALERT_EN, + .info = &ad7993_4_7_8_info, + }, +}; + +static int ad799x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct ad799x_state *st; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, indio_dev); + + st->id = id->driver_data; + st->chip_info = &ad799x_chip_info_tbl[st->id]; + st->config = st->chip_info->default_config; + + /* TODO: Add pdata options for filtering and bit delay */ + + st->reg = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + ret = regulator_enable(st->reg); + if (ret) + return ret; + st->vref = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(st->vref)) { + ret = PTR_ERR(st->vref); + goto error_disable_reg; + } + ret = regulator_enable(st->vref); + if (ret) + goto error_disable_reg; + + st->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->info = st->chip_info->info; + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channel; + indio_dev->num_channels = st->chip_info->num_channels; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ad799x_trigger_handler, NULL); + if (ret) + goto error_disable_reg; + + if (client->irq > 0) { + ret = devm_request_threaded_irq(&client->dev, + client->irq, + NULL, + ad799x_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + client->name, + indio_dev); + if (ret) + goto error_cleanup_ring; + } + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_ring; + + return 0; + +error_cleanup_ring: + iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: + if (!IS_ERR(st->vref)) + regulator_disable(st->vref); + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); + + return ret; +} + +static int ad799x_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ad799x_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + iio_triggered_buffer_cleanup(indio_dev); + if (!IS_ERR(st->vref)) + regulator_disable(st->vref); + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); + kfree(st->rx_buf); + + return 0; +} + +static const struct i2c_device_id ad799x_id[] = { + { "ad7991", ad7991 }, + { "ad7995", ad7995 }, + { "ad7999", ad7999 }, + { "ad7992", ad7992 }, + { "ad7993", ad7993 }, + { "ad7994", ad7994 }, + { "ad7997", ad7997 }, + { "ad7998", ad7998 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_id); + +static struct i2c_driver ad799x_driver = { + .driver = { + .name = "ad799x", + }, + .probe = ad799x_probe, + .remove = ad799x_remove, + .id_table = ad799x_id, +}; +module_i2c_driver(ad799x_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD799x ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index ed23cce..b87e382 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -37,17 +37,6 @@ config AD7606_IFACE_SPI Say yes here to include parallel interface support on the AD7606 ADC driver. -config AD799X - tristate "Analog Devices AD799x ADC driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices: - ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 - i2c analog to digital converters (ADC). Provides direct access - via sysfs. - config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index b2d35f8..afdcd1f 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -8,9 +8,6 @@ ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o -ad799x-y := ad799x_core.o -obj-$(CONFIG_AD799X) += ad799x.o - obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7816) += ad7816.o diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c deleted file mode 100644 index bcbf610..0000000 --- a/drivers/staging/iio/adc/ad799x_core.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * iio/adc/ad799x.c - * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. - * - * based on iio/adc/max1363 - * Copyright (C) 2008-2010 Jonathan Cameron - * - * based on linux/drivers/i2c/chips/max123x - * Copyright (C) 2002-2004 Stefan Eletzhofer - * - * based on linux/drivers/acron/char/pcf8583.c - * Copyright (C) 2000 Russell King - * - * 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. - * - * ad799x.c - * - * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, - * ad7998 and similar chips. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define AD799X_CHANNEL_SHIFT 4 -#define AD799X_STORAGEBITS 16 -/* - * AD7991, AD7995 and AD7999 defines - */ - -#define AD7991_REF_SEL 0x08 -#define AD7991_FLTR 0x04 -#define AD7991_BIT_TRIAL_DELAY 0x02 -#define AD7991_SAMPLE_DELAY 0x01 - -/* - * AD7992, AD7993, AD7994, AD7997 and AD7998 defines - */ - -#define AD7998_FLTR 0x08 -#define AD7998_ALERT_EN 0x04 -#define AD7998_BUSY_ALERT 0x02 -#define AD7998_BUSY_ALERT_POL 0x01 - -#define AD7998_CONV_RES_REG 0x0 -#define AD7998_ALERT_STAT_REG 0x1 -#define AD7998_CONF_REG 0x2 -#define AD7998_CYCLE_TMR_REG 0x3 - -#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4) -#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) -#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) - -#define AD7998_CYC_MASK 0x7 -#define AD7998_CYC_DIS 0x0 -#define AD7998_CYC_TCONF_32 0x1 -#define AD7998_CYC_TCONF_64 0x2 -#define AD7998_CYC_TCONF_128 0x3 -#define AD7998_CYC_TCONF_256 0x4 -#define AD7998_CYC_TCONF_512 0x5 -#define AD7998_CYC_TCONF_1024 0x6 -#define AD7998_CYC_TCONF_2048 0x7 - -#define AD7998_ALERT_STAT_CLEAR 0xFF - -/* - * AD7997 and AD7997 defines - */ - -#define AD7997_8_READ_SINGLE 0x80 -#define AD7997_8_READ_SEQUENCE 0x70 -/* TODO: move this into a common header */ -#define RES_MASK(bits) ((1 << (bits)) - 1) - -enum { - ad7991, - ad7995, - ad7999, - ad7992, - ad7993, - ad7994, - ad7997, - ad7998 -}; - -/** - * struct ad799x_chip_info - chip specifc information - * @channel: channel specification - * @num_channels: number of channels - * @monitor_mode: whether the chip supports monitor interrupts - * @default_config: device default configuration - * @event_attrs: pointer to the monitor event attribute group - */ -struct ad799x_chip_info { - struct iio_chan_spec channel[9]; - int num_channels; - u16 default_config; - const struct iio_info *info; -}; - -struct ad799x_state { - struct i2c_client *client; - const struct ad799x_chip_info *chip_info; - struct regulator *reg; - struct regulator *vref; - unsigned id; - u16 config; - - u8 *rx_buf; - unsigned int transfer_size; -}; - -/** - * ad799x_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ -static irqreturn_t ad799x_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad799x_state *st = iio_priv(indio_dev); - int b_sent; - u8 cmd; - - switch (st->id) { - case ad7991: - case ad7995: - case ad7999: - cmd = st->config | - (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); - break; - case ad7992: - case ad7993: - case ad7994: - cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | - AD7998_CONV_RES_REG; - break; - case ad7997: - case ad7998: - cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; - break; - default: - cmd = 0; - } - - b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, st->transfer_size, st->rx_buf); - if (b_sent < 0) - goto out; - - iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); -out: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -/* - * ad799x register access by I2C - */ -static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_read_word_swapped(client, reg); - if (ret < 0) { - dev_err(&client->dev, "I2C read error\n"); - return ret; - } - - *data = (u16)ret; - - return 0; -} - -static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_read_byte_data(client, reg); - if (ret < 0) { - dev_err(&client->dev, "I2C read error\n"); - return ret; - } - - *data = (u8)ret; - - return 0; -} - -static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_write_word_swapped(client, reg, data); - if (ret < 0) - dev_err(&client->dev, "I2C write error\n"); - - return ret; -} - -static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) -{ - struct i2c_client *client = st->client; - int ret = 0; - - ret = i2c_smbus_write_byte_data(client, reg, data); - if (ret < 0) - dev_err(&client->dev, "I2C write error\n"); - - return ret; -} - -static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct ad799x_state *st = iio_priv(indio_dev); - - kfree(st->rx_buf); - st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!st->rx_buf) - return -ENOMEM; - - st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2; - - switch (st->id) { - case ad7997: - case ad7998: - return ad799x_i2c_write16(st, AD7998_CONF_REG, - st->config | (*scan_mask << AD799X_CHANNEL_SHIFT)); - default: - break; - } - - return 0; -} - -static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) -{ - u16 rxbuf; - u8 cmd; - int ret; - - switch (st->id) { - case ad7991: - case ad7995: - case ad7999: - cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT); - break; - case ad7992: - case ad7993: - case ad7994: - cmd = (1 << ch) << AD799X_CHANNEL_SHIFT; - break; - case ad7997: - case ad7998: - cmd = (ch << AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE; - break; - default: - return -EINVAL; - } - - ret = ad799x_i2c_read16(st, cmd, &rxbuf); - if (ret < 0) - return ret; - - return rxbuf; -} - -static int ad799x_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret; - struct ad799x_state *st = iio_priv(indio_dev); - - switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad799x_scan_direct(st, chan->scan_index); - mutex_unlock(&indio_dev->mlock); - - if (ret < 0) - return ret; - *val = (ret >> chan->scan_type.shift) & - RES_MASK(chan->scan_type.realbits); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(st->vref); - if (ret < 0) - return ret; - *val = ret / 1000; - *val2 = chan->scan_type.realbits; - return IIO_VAL_FRACTIONAL_LOG2; - } - return -EINVAL; -} -static const unsigned int ad7998_frequencies[] = { - [AD7998_CYC_DIS] = 0, - [AD7998_CYC_TCONF_32] = 15625, - [AD7998_CYC_TCONF_64] = 7812, - [AD7998_CYC_TCONF_128] = 3906, - [AD7998_CYC_TCONF_512] = 976, - [AD7998_CYC_TCONF_1024] = 488, - [AD7998_CYC_TCONF_2048] = 244, -}; -static ssize_t ad799x_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad799x_state *st = iio_priv(indio_dev); - - int ret; - u8 val; - ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); - if (ret) - return ret; - - val &= AD7998_CYC_MASK; - - return sprintf(buf, "%u\n", ad7998_frequencies[val]); -} - -static ssize_t ad799x_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad799x_state *st = iio_priv(indio_dev); - - long val; - int ret, i; - u8 t; - - ret = kstrtol(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); - if (ret) - goto error_ret_mutex; - /* Wipe the bits clean */ - t &= ~AD7998_CYC_MASK; - - for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) - if (val == ad7998_frequencies[i]) - break; - if (i == ARRAY_SIZE(ad7998_frequencies)) { - ret = -EINVAL; - goto error_ret_mutex; - } - t |= i; - ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); - -error_ret_mutex: - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -static int ad799x_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - return 1; -} - -static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, - enum iio_event_direction dir, - enum iio_event_info info) -{ - switch (info) { - case IIO_EV_INFO_VALUE: - if (dir == IIO_EV_DIR_FALLING) - return AD7998_DATALOW_REG(chan->channel); - else - return AD7998_DATAHIGH_REG(chan->channel); - case IIO_EV_INFO_HYSTERESIS: - return AD7998_HYST_REG(chan->channel); - default: - return -EINVAL; - } - - return 0; -} - -static int ad799x_write_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - int ret; - struct ad799x_state *st = iio_priv(indio_dev); - - mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), - val); - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -static int ad799x_read_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - int ret; - struct ad799x_state *st = iio_priv(indio_dev); - u16 valin; - - mutex_lock(&indio_dev->mlock); - ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), - &valin); - mutex_unlock(&indio_dev->mlock); - if (ret < 0) - return ret; - *val = valin; - - return IIO_VAL_INT; -} - -static irqreturn_t ad799x_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct ad799x_state *st = iio_priv(private); - u8 status; - int i, ret; - - ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status); - if (ret) - goto done; - - if (!status) - goto done; - - ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); - - for (i = 0; i < 8; i++) { - if (status & (1 << i)) - iio_push_event(indio_dev, - i & 0x1 ? - IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, - (i >> 1), - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING) : - IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, - (i >> 1), - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - iio_get_time_ns()); - } - -done: - return IRQ_HANDLED; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad799x_read_frequency, - ad799x_write_frequency); -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); - -static struct attribute *ad799x_event_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static struct attribute_group ad799x_event_attrs_group = { - .attrs = ad799x_event_attributes, - .name = "events", -}; - -static const struct iio_info ad7991_info = { - .read_raw = &ad799x_read_raw, - .driver_module = THIS_MODULE, -}; - -static const struct iio_info ad7993_4_7_8_info = { - .read_raw = &ad799x_read_raw, - .event_attrs = &ad799x_event_attrs_group, - .read_event_config = &ad799x_read_event_config, - .read_event_value = &ad799x_read_event_value, - .write_event_value = &ad799x_write_event_value, - .driver_module = THIS_MODULE, - .update_scan_mode = ad7997_8_update_scan_mode, -}; - -static const struct iio_event_spec ad799x_events[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), - }, -}; - -#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \ - .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), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (_realbits), \ - .storagebits = 16, \ - .shift = 12 - (_realbits), \ - .endianness = IIO_BE, \ - }, \ - .event_spec = _ev_spec, \ - .num_event_specs = _num_ev_spec, \ -} - -#define AD799X_CHANNEL(_index, _realbits) \ - _AD799X_CHANNEL(_index, _realbits, NULL, 0) - -#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \ - _AD799X_CHANNEL(_index, _realbits, ad799x_events, \ - ARRAY_SIZE(ad799x_events)) - -static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { - [ad7991] = { - .channel = { - AD799X_CHANNEL(0, 12), - AD799X_CHANNEL(1, 12), - AD799X_CHANNEL(2, 12), - AD799X_CHANNEL(3, 12), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, - .num_channels = 5, - .info = &ad7991_info, - }, - [ad7995] = { - .channel = { - AD799X_CHANNEL(0, 10), - AD799X_CHANNEL(1, 10), - AD799X_CHANNEL(2, 10), - AD799X_CHANNEL(3, 10), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, - .num_channels = 5, - .info = &ad7991_info, - }, - [ad7999] = { - .channel = { - AD799X_CHANNEL(0, 8), - AD799X_CHANNEL(1, 8), - AD799X_CHANNEL(2, 8), - AD799X_CHANNEL(3, 8), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, - .num_channels = 5, - .info = &ad7991_info, - }, - [ad7992] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - IIO_CHAN_SOFT_TIMESTAMP(3), - }, - .num_channels = 3, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, - }, - [ad7993] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 10), - AD799X_CHANNEL_WITH_EVENTS(1, 10), - AD799X_CHANNEL_WITH_EVENTS(2, 10), - AD799X_CHANNEL_WITH_EVENTS(3, 10), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, - .num_channels = 5, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, - }, - [ad7994] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - AD799X_CHANNEL_WITH_EVENTS(2, 12), - AD799X_CHANNEL_WITH_EVENTS(3, 12), - IIO_CHAN_SOFT_TIMESTAMP(4), - }, - .num_channels = 5, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, - }, - [ad7997] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 10), - AD799X_CHANNEL_WITH_EVENTS(1, 10), - AD799X_CHANNEL_WITH_EVENTS(2, 10), - AD799X_CHANNEL_WITH_EVENTS(3, 10), - AD799X_CHANNEL(4, 10), - AD799X_CHANNEL(5, 10), - AD799X_CHANNEL(6, 10), - AD799X_CHANNEL(7, 10), - IIO_CHAN_SOFT_TIMESTAMP(8), - }, - .num_channels = 9, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, - }, - [ad7998] = { - .channel = { - AD799X_CHANNEL_WITH_EVENTS(0, 12), - AD799X_CHANNEL_WITH_EVENTS(1, 12), - AD799X_CHANNEL_WITH_EVENTS(2, 12), - AD799X_CHANNEL_WITH_EVENTS(3, 12), - AD799X_CHANNEL(4, 12), - AD799X_CHANNEL(5, 12), - AD799X_CHANNEL(6, 12), - AD799X_CHANNEL(7, 12), - IIO_CHAN_SOFT_TIMESTAMP(8), - }, - .num_channels = 9, - .default_config = AD7998_ALERT_EN, - .info = &ad7993_4_7_8_info, - }, -}; - -static int ad799x_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct ad799x_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - /* this is only used for device removal purposes */ - i2c_set_clientdata(client, indio_dev); - - st->id = id->driver_data; - st->chip_info = &ad799x_chip_info_tbl[st->id]; - st->config = st->chip_info->default_config; - - /* TODO: Add pdata options for filtering and bit delay */ - - st->reg = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); - ret = regulator_enable(st->reg); - if (ret) - return ret; - st->vref = devm_regulator_get(&client->dev, "vref"); - if (IS_ERR(st->vref)) { - ret = PTR_ERR(st->vref); - goto error_disable_reg; - } - ret = regulator_enable(st->vref); - if (ret) - goto error_disable_reg; - - st->client = client; - - indio_dev->dev.parent = &client->dev; - indio_dev->name = id->name; - indio_dev->info = st->chip_info->info; - - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = st->chip_info->num_channels; - - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ad799x_trigger_handler, NULL); - if (ret) - goto error_disable_reg; - - if (client->irq > 0) { - ret = devm_request_threaded_irq(&client->dev, - client->irq, - NULL, - ad799x_event_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - client->name, - indio_dev); - if (ret) - goto error_cleanup_ring; - } - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_ring; - - return 0; - -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - if (!IS_ERR(st->vref)) - regulator_disable(st->vref); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return ret; -} - -static int ad799x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ad799x_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - if (!IS_ERR(st->vref)) - regulator_disable(st->vref); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - kfree(st->rx_buf); - - return 0; -} - -static const struct i2c_device_id ad799x_id[] = { - { "ad7991", ad7991 }, - { "ad7995", ad7995 }, - { "ad7999", ad7999 }, - { "ad7992", ad7992 }, - { "ad7993", ad7993 }, - { "ad7994", ad7994 }, - { "ad7997", ad7997 }, - { "ad7998", ad7998 }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, ad799x_id); - -static struct i2c_driver ad799x_driver = { - .driver = { - .name = "ad799x", - }, - .probe = ad799x_probe, - .remove = ad799x_remove, - .id_table = ad799x_id, -}; -module_i2c_driver(ad799x_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD799x ADC"); -MODULE_LICENSE("GPL v2"); -- cgit v1.1 From 2816ac64ac46c4017355a49331250e5c016dc2c0 Mon Sep 17 00:00:00 2001 From: Angelo Compagnucci Date: Sun, 3 Aug 2014 23:22:00 +0100 Subject: Add support for Microchip Technology's MCP3426/7/8 ADC This patch extends previous mcp3422 driver to support missing members of the family, mcp3426/7/8. Signed-off-by: Angelo Compagnucci Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 7 ++++--- drivers/iio/adc/mcp3422.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index a036811..1dffa2d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -157,11 +157,12 @@ config MCP320X called mcp320x. config MCP3422 - tristate "Microchip Technology MCP3422/3/4 driver" + tristate "Microchip Technology MCP3422/3/4/6/7/8 driver" depends on I2C help - Say yes here to build support for Microchip Technology's MCP3422, - MCP3423 or MCP3424 analog to digital converters. + Say yes here to build support for Microchip Technology's + MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428 + analog to digital converters. This driver can also be built as a module. If so, the module will be called mcp3422. diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 47dcb34..5167225 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -1,10 +1,11 @@ /* - * mcp3422.c - driver for the Microchip mcp3422/3/4 chip family + * mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family * * Copyright (C) 2013, Angelo Compagnucci * Author: Angelo Compagnucci * * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf + * http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf * * This driver exports the value of analog input voltage to sysfs, the * voltage unit is nV. @@ -96,6 +97,7 @@ static const int mcp3422_sign_extend[4] = { /* Client data (each client gets its own) */ struct mcp3422 { struct i2c_client *i2c; + u8 id; u8 config; u8 pga[4]; struct mutex lock; @@ -238,6 +240,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, temp = MCP3422_SRATE_15; break; case 3: + if (adc->id > 4) + return -EINVAL; temp = MCP3422_SRATE_3; break; default: @@ -271,6 +275,17 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, } } +static ssize_t mcp3422_show_samp_freqs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + + if (adc->id > 4) + return sprintf(buf, "240 60 15\n"); + + return sprintf(buf, "240 60 15 3\n"); +} + static ssize_t mcp3422_show_scales(struct device *dev, struct device_attribute *attr, char *buf) { @@ -284,12 +299,13 @@ static ssize_t mcp3422_show_scales(struct device *dev, mcp3422_scales[sample_rate][3]); } -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("240 60 15 3"); +static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, + mcp3422_show_samp_freqs, NULL, 0); static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, mcp3422_show_scales, NULL, 0); static struct attribute *mcp3422_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, NULL, }; @@ -335,6 +351,7 @@ static int mcp3422_probe(struct i2c_client *client, adc = iio_priv(indio_dev); adc->i2c = client; + adc->id = (u8)(id->driver_data); mutex_init(&adc->lock); @@ -343,13 +360,16 @@ static int mcp3422_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp3422_info; - switch ((unsigned int)(id->driver_data)) { + switch (adc->id) { case 2: case 3: + case 6: + case 7: indio_dev->channels = mcp3422_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); break; case 4: + case 8: indio_dev->channels = mcp3424_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); break; @@ -375,6 +395,9 @@ static const struct i2c_device_id mcp3422_id[] = { { "mcp3422", 2 }, { "mcp3423", 3 }, { "mcp3424", 4 }, + { "mcp3426", 6 }, + { "mcp3427", 7 }, + { "mcp3428", 8 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); @@ -399,5 +422,5 @@ static struct i2c_driver mcp3422_driver = { module_i2c_driver(mcp3422_driver); MODULE_AUTHOR("Angelo Compagnucci "); -MODULE_DESCRIPTION("Microchip mcp3422/3/4 driver"); +MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.1 From ef4b4856593fc3d9d169bededdaf7acf62f83a52 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 3 Jan 2014 22:24:00 +0000 Subject: iio:core: Fix bug in length of event info_mask and catch unhandled bits set in masks. The unhandled bits case was highlighted by smatch: CHECK drivers/iio/industrialio-core.c drivers/iio/industrialio-core.c:719 iio_device_add_info_mask_type() error: buffer overflow 'iio_chan_info_postfix' 17 <= 31 CC [M] drivers/iio/industrialio-core.o CHECK drivers/iio/industrialio-event.c drivers/iio/industrialio-event.c:327 iio_device_add_event() error: buffer overflow 'iio_ev_info_text' 3 <= 3 The incorrect limit for the for_each_set_bit loop was noticed whilst fixing this other case. Note that as we only have 3 possible entries a the moment and the value was set to 4, the bug would not have any effect currently. It will bite fairly soon though, so best fix it now. Signed-off-by: Jonathan Cameron Cc: Lars-Peter Clausen Cc: Dan Carpenter --- drivers/iio/industrialio-core.c | 2 ++ drivers/iio/industrialio-event.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 1375921..184444d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -716,6 +716,8 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, int i, ret, attrcount = 0; for_each_set_bit(i, infomask, sizeof(infomask)*8) { + if (i >= ARRAY_SIZE(iio_chan_info_postfix)) + return -EINVAL; ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], chan, &iio_read_channel_info, diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index ea6e06b..dddfb0f 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -321,7 +321,9 @@ static int iio_device_add_event(struct iio_dev *indio_dev, char *postfix; int ret; - for_each_set_bit(i, mask, sizeof(*mask)) { + for_each_set_bit(i, mask, sizeof(*mask)*8) { + if (i >= ARRAY_SIZE(iio_ev_info_text)) + return -EINVAL; postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_ev_type_text[type], iio_ev_dir_text[dir], iio_ev_info_text[i]); -- cgit v1.1 From 239670ef48dfff9cf07675acdb3bb7deee4853e1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 3 Jan 2014 22:08:00 +0000 Subject: iio:gyro:itg3200 - drop unreachable return ret. Highlighted by smatch CHECK drivers/iio/gyro/itg3200_core.c drivers/iio/gyro/itg3200_core.c:114 itg3200_read_raw() info: ignoring unreachable code. Signed-off-by: Jonathan Cameron Cc: Neil Brown Cc: Dan Carpenter --- drivers/iio/gyro/itg3200_core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 4d3f3b9..8295e31 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -110,8 +110,6 @@ static int itg3200_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - - return ret; } static ssize_t itg3200_read_frequency(struct device *dev, -- cgit v1.1 From 6027c077f62f11818a7645151119f8718862d764 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 19 Mar 2014 16:56:00 +0000 Subject: iio: ak8975 : Add AK8963 compatibility mode support AK8963 and AK8975 use same register definitions, except the range of X,Y,Z values. Added support of 8963 based on i2c_device_id. Unfortunately there is no way to detect the type via registers, both device registers return 0x48 as id of chipset. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/Kconfig | 3 ++- drivers/iio/magnetometer/ak8975.c | 34 +++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index d86d226..05a364c54 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -11,7 +11,8 @@ config AK8975 depends on GPIOLIB help Say yes here to build support for Asahi Kasei AK8975 3-Axis - Magnetometer. + Magnetometer. This driver can also support AK8963, if i2c + device name is identified as ak8963. To compile this driver as a module, choose M here: the module will be called ak8975. diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 74866d1..0f1ca53 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -85,7 +85,14 @@ #define AK8975_MAX_CONVERSION_TIMEOUT 500 #define AK8975_CONVERSION_DONE_POLL_TIME 10 #define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) -#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256) +#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256) +#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256) + +/* Compatible Asahi Kasei Compass parts */ +enum asahi_compass_chipset { + AK8975, + AK8963, +}; /* * Per-instance context data for the device. @@ -101,6 +108,7 @@ struct ak8975_data { int eoc_irq; wait_queue_head_t data_ready_queue; unsigned long flags; + enum asahi_compass_chipset chipset; }; static const int ak8975_index_to_reg[] = { @@ -272,9 +280,21 @@ static int ak8975_setup(struct i2c_client *client) * Since ASA doesn't change, we cache the resultant scale factor into the * device context in ak8975_setup(). */ - data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]); - data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]); - data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]); + if (data->chipset == AK8963) { + /* + * H range is +-8190 and magnetometer range is +-4912. + * So HuT using the above explanation for 8975, + * 4912/8190 = ~ 6/10. + * So the Hadj should use 6/10 instead of 3/10. + */ + data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]); + } else { + data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]); + } return 0; } @@ -499,6 +519,9 @@ static int ak8975_probe(struct i2c_client *client, data->eoc_gpio = eoc_gpio; data->eoc_irq = 0; + data->chipset = (enum asahi_compass_chipset)(id->driver_data); + dev_dbg(&client->dev, "Asahi compass chip %s\n", id->name); + /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); if (err < 0) { @@ -552,7 +575,8 @@ static int ak8975_remove(struct i2c_client *client) } static const struct i2c_device_id ak8975_id[] = { - {"ak8975", 0}, + {"ak8975", AK8975}, + {"ak8963", AK8963}, {} }; -- cgit v1.1 From d913971ecaf31d7d5a6836224b669e1972469445 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 19 Mar 2014 16:56:00 +0000 Subject: iio: ak8975: Added ACPI enumeration Added capability so that this device can be enumerated via ACPI. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 0f1ca53..f5c1d41 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -475,6 +476,27 @@ static const struct iio_info ak8975_info = { .driver_module = THIS_MODULE, }; +static const struct acpi_device_id ak_acpi_match[] = { + {"AK8975", AK8975}, + {"AK8963", AK8963}, + {"INVN6500", AK8963}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + +static char *ak8975_match_acpi_device(struct device *dev, + enum asahi_compass_chipset *chipset) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + *chipset = (int)id->driver_data; + + return (char *)dev_name(dev); +} + static int ak8975_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -482,6 +504,7 @@ static int ak8975_probe(struct i2c_client *client, struct iio_dev *indio_dev; int eoc_gpio; int err; + char *name = NULL; /* Grab and set up the supplied GPIO. */ if (client->dev.platform_data) @@ -519,8 +542,18 @@ static int ak8975_probe(struct i2c_client *client, data->eoc_gpio = eoc_gpio; data->eoc_irq = 0; - data->chipset = (enum asahi_compass_chipset)(id->driver_data); - dev_dbg(&client->dev, "Asahi compass chip %s\n", id->name); + /* id will be NULL when enumerated via ACPI */ + if (id) { + data->chipset = + (enum asahi_compass_chipset)(id->driver_data); + 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; + } + dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); @@ -538,7 +571,7 @@ static int ak8975_probe(struct i2c_client *client, indio_dev->info = &ak8975_info; indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; - + indio_dev->name = name; err = iio_device_register(indio_dev); if (err < 0) goto exit_free_iio; @@ -593,6 +626,7 @@ static struct i2c_driver ak8975_driver = { .driver = { .name = "ak8975", .of_match_table = ak8975_of_match, + .acpi_match_table = ACPI_PTR(ak_acpi_match), }, .probe = ak8975_probe, .remove = ak8975_remove, -- cgit v1.1 From 6f174fd312d50abf3e98c0c5f7adf0cf434ae705 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 19 Mar 2014 16:56:00 +0000 Subject: iio: imu: inv_mpu6050: Add compatibity with MPU6500 Adding MPU6500 in target list for this driver. Description: Source Document: MPU-6500 Register Map and Descriptions Revision 2.1 Section 3: Register Map This section describes difference in terms device programmability between MPU6050 and MPU6500. These are different registers, which differs between MPU6050 and MPU6500. Addr Name --------------------- 1E LP_ACCEL_ODR 6C PWR_MGMT_2 77 XA_OFFSET_H 78 XA_OFFSET_L 7A YA_OFFSET_H 7B YA_OFFSET_L 7D ZA_OFFSET_H 7E ZA_OFFSET_L But the current MPU6050 driver doesn't use registers which are different except PWR_MGMT_2. The difference is support of "LP_WAKE_CTRL" at bit6-7 in MPU6050 mode. In MPU6500 they are not defined. In current mpu6050 driver, only values used for this register are for standby mode for gyro and accelerometer. In both case frequency of wakeups is set to default and not using bit 6-7. So this driver van as well support MPU6500. In addition MPU6500 can run MPU6050 mode by changing device trim settings. So changing config comments to allow MPU6500 to use this driver. When the driver is enhanced to support more functions, i2c driver data INV_MPU6500 or "WHO_AM_I" register can be used to add additional functionality. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/Kconfig | 2 ++ drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 1 + drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 361b232..2d0608b 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -9,6 +9,8 @@ config INV_MPU6050_IIO select IIO_TRIGGERED_BUFFER help This driver supports the Invensense MPU6050 devices. + This driver can also support MPU6500 in MPU6050 compatibility mode + and also in MPU6500 mode with some limitations. It is a gyroscope/accelerometer combo device. This driver can be built as a module. The module will be called inv-mpu6050. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index cb9f96b..af287bf 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -764,6 +764,7 @@ static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); */ static const struct i2c_device_id inv_mpu_id[] = { {"mpu6050", INV_MPU6050}, + {"mpu6500", INV_MPU6500}, {} }; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 0ab382b..e779931 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -59,6 +59,7 @@ struct inv_mpu6050_reg_map { /*device enum */ enum inv_devices { INV_MPU6050, + INV_MPU6500, INV_NUM_PARTS }; -- cgit v1.1 From b64aef7034572b1f669bf295b88332ea0b149050 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear adc - prefix defines to avoid namespace clashes. Signed-off-by: Jonathan Cameron Acked-by: Stefan Roese Acked-by: Hartmut Knaack --- drivers/staging/iio/adc/spear_adc.c | 73 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 970d9ed..49293f9 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -22,39 +22,36 @@ #include #include -/* - * SPEAR registers definitions - */ - -#define SCAN_RATE_LO(x) ((x) & 0xFFFF) -#define SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) -#define CLK_LOW(x) (((x) & 0xf) << 0) -#define CLK_HIGH(x) (((x) & 0xf) << 4) +/* SPEAR registers definitions */ +#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) +#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) +#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0) +#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4) /* Bit definitions for SPEAR_ADC_STATUS */ -#define START_CONVERSION (1 << 0) -#define CHANNEL_NUM(x) ((x) << 1) -#define ADC_ENABLE (1 << 4) -#define AVG_SAMPLE(x) ((x) << 5) -#define VREF_INTERNAL (1 << 9) +#define SPEAR_ADC_STATUS_START_CONVERSION (1 << 0) +#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) +#define SPEAR_ADC_STATUS_ADC_ENABLE (1 << 4) +#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) +#define SPEAR_ADC_STATUS_VREF_INTERNAL (1 << 9) -#define DATA_MASK 0x03ff -#define DATA_BITS 10 +#define SPEAR_ADC_DATA_MASK 0x03ff +#define SPEAR_ADC_DATA_BITS 10 -#define MOD_NAME "spear-adc" +#define SPEAR_ADC_MOD_NAME "spear-adc" -#define ADC_CHANNEL_NUM 8 +#define SPEAR_ADC_CHANNEL_NUM 8 -#define CLK_MIN 2500000 -#define CLK_MAX 20000000 +#define SPEAR_ADC_CLK_MIN 2500000 +#define SPEAR_ADC_CLK_MAX 20000000 struct adc_regs_spear3xx { u32 status; u32 average; u32 scan_rate; u32 clk; /* Not avail for 1340 & 1310 */ - u32 ch_ctrl[ADC_CHANNEL_NUM]; - u32 ch_data[ADC_CHANNEL_NUM]; + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + u32 ch_data[SPEAR_ADC_CHANNEL_NUM]; }; struct chan_data { @@ -66,8 +63,8 @@ struct adc_regs_spear6xx { u32 status; u32 pad[2]; u32 clk; - u32 ch_ctrl[ADC_CHANNEL_NUM]; - struct chan_data ch_data[ADC_CHANNEL_NUM]; + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM]; u32 scan_rate_lo; u32 scan_rate_hi; struct chan_data average; @@ -106,7 +103,7 @@ static void spear_adc_set_clk(struct spear_adc_info *info, u32 val) clk_high = count - clk_low; info->current_clk = apb_clk / count; - __raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high), + __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), &info->adc_base_spear6xx->clk); } @@ -120,19 +117,19 @@ static u32 spear_adc_get_average(struct spear_adc_info *info) { if (of_device_is_compatible(info->np, "st,spear600-adc")) { return __raw_readl(&info->adc_base_spear6xx->average.msb) & - DATA_MASK; + SPEAR_ADC_DATA_MASK; } else { return __raw_readl(&info->adc_base_spear3xx->average) & - DATA_MASK; + SPEAR_ADC_DATA_MASK; } } static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate) { if (of_device_is_compatible(info->np, "st,spear600-adc")) { - __raw_writel(SCAN_RATE_LO(rate), + __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), &info->adc_base_spear6xx->scan_rate_lo); - __raw_writel(SCAN_RATE_HI(rate), + __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), &info->adc_base_spear6xx->scan_rate_hi); } else { __raw_writel(rate, &info->adc_base_spear3xx->scan_rate); @@ -152,11 +149,12 @@ static int spear_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); - status = CHANNEL_NUM(chan->channel) | - AVG_SAMPLE(info->avg_samples) | - START_CONVERSION | ADC_ENABLE; + status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | + SPEAR_ADC_STATUS_AVG_SAMPLE(info->avg_samples) | + SPEAR_ADC_STATUS_START_CONVERSION | + SPEAR_ADC_STATUS_ADC_ENABLE; if (info->vref_external == 0) - status |= VREF_INTERNAL; + status |= SPEAR_ADC_STATUS_VREF_INTERNAL; spear_adc_set_status(info, status); wait_for_completion(&info->completion); /* set by ISR */ @@ -168,7 +166,7 @@ static int spear_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = info->vref_external; - *val2 = DATA_BITS; + *val2 = SPEAR_ADC_DATA_BITS; return IIO_VAL_FRACTIONAL_LOG2; } @@ -253,7 +251,7 @@ static ssize_t spear_adc_write_frequency(struct device *dev, mutex_lock(&indio_dev->mlock); - if ((lval < CLK_MIN) || (lval > CLK_MAX)) { + if ((lval < SPEAR_ADC_CLK_MIN) || (lval > SPEAR_ADC_CLK_MAX)) { ret = -EINVAL; goto out; } @@ -339,7 +337,8 @@ static int spear_adc_probe(struct platform_device *pdev) goto errout3; } - ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info); + ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, + info); if (ret < 0) { dev_err(dev, "failed requesting interrupt\n"); goto errout3; @@ -370,7 +369,7 @@ static int spear_adc_probe(struct platform_device *pdev) init_completion(&info->completion); - iodev->name = MOD_NAME; + iodev->name = SPEAR_ADC_MOD_NAME; iodev->dev.parent = dev; iodev->info = &spear_adc_iio_info; iodev->modes = INDIO_DIRECT_MODE; @@ -419,7 +418,7 @@ static struct platform_driver spear_adc_driver = { .probe = spear_adc_probe, .remove = spear_adc_remove, .driver = { - .name = MOD_NAME, + .name = SPEAR_ADC_MOD_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(spear_adc_dt_ids), }, -- cgit v1.1 From a8375a9952c1864bea1047a8087a81747b09f3ae Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear_adc drop initialization of unused scan_type As the driver does not support the buffered interfaces of IIO this is not used. Signed-off-by: Jonathan Cameron Acked-by: Stefan Roese --- drivers/staging/iio/adc/spear_adc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 49293f9..c4e928b 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -179,10 +179,6 @@ static int spear_read_raw(struct iio_dev *indio_dev, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .channel = idx, \ - .scan_type = { \ - .sign = 'u', \ - .storagebits = 16, \ - }, \ } static const struct iio_chan_spec spear_adc_iio_channels[] = { -- cgit v1.1 From 932de74ba335358e2521f951c59bbda2746c5aef Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear_adc use info_mask_shared_by_all for samp freq Using the core support makes this element available to in kernel users as well as to userspace under exactly the same interface as before. The intent is to move all sampling frequency control to this approach throughout IIO. Drop unused clk_high and clk_low whilst we are at it. Signed-off-by: Jonathan Cameron Acked-by: Stefan Roese Acked-by: Hartmut Knaack --- drivers/staging/iio/adc/spear_adc.c | 92 +++++++++++++------------------------ 1 file changed, 33 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index c4e928b..44a129f 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -168,16 +168,48 @@ static int spear_read_raw(struct iio_dev *indio_dev, *val = info->vref_external; *val2 = SPEAR_ADC_DATA_BITS; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = info->current_clk; + return IIO_VAL_INT; } return -EINVAL; } +static int spear_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct spear_adc_info *info = iio_priv(indio_dev); + int ret = 0; + + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + if ((val < SPEAR_ADC_CLK_MIN) || + (val > SPEAR_ADC_CLK_MAX) || + (val2 != 0)) { + ret = -EINVAL; + goto out; + } + + spear_adc_set_clk(info, val); + +out: + mutex_unlock(&indio_dev->mlock); + return ret; +} + #define SPEAR_ADC_CHAN(idx) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ .channel = idx, \ } @@ -219,67 +251,9 @@ static int spear_adc_configure(struct spear_adc_info *info) return 0; } -static ssize_t spear_adc_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct spear_adc_info *info = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", info->current_clk); -} - -static ssize_t spear_adc_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct spear_adc_info *info = iio_priv(indio_dev); - u32 clk_high, clk_low, count; - u32 apb_clk = clk_get_rate(info->clk); - unsigned long lval; - int ret; - - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - - if ((lval < SPEAR_ADC_CLK_MIN) || (lval > SPEAR_ADC_CLK_MAX)) { - ret = -EINVAL; - goto out; - } - - count = (apb_clk + lval - 1) / lval; - clk_low = count / 2; - clk_high = count - clk_low; - info->current_clk = apb_clk / count; - spear_adc_set_clk(info, lval); - -out: - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - spear_adc_read_frequency, - spear_adc_write_frequency); - -static struct attribute *spear_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group spear_attribute_group = { - .attrs = spear_attributes, -}; - static const struct iio_info spear_adc_iio_info = { .read_raw = &spear_read_raw, - .attrs = &spear_attribute_group, + .write_raw = &spear_adc_write_raw, .driver_module = THIS_MODULE, }; -- cgit v1.1 From b586e5d9eee038b8ee6f846cdb6cf2fcbcb2f4ed Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear rename device specific state structure to _state Also rename instances of it to st. This brings the driver inline with the conventions of IIO and avoids some naming confusion with some IIO structures which also use the _info postfix. Signed-off-by: Jonathan Cameron Acked-by: Hartmut Knaack --- drivers/staging/iio/adc/spear_adc.c | 126 ++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 44a129f..3003e89 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -70,7 +70,7 @@ struct adc_regs_spear6xx { struct chan_data average; }; -struct spear_adc_info { +struct spear_adc_state { struct device_node *np; struct adc_regs_spear3xx __iomem *adc_base_spear3xx; struct adc_regs_spear6xx __iomem *adc_base_spear6xx; @@ -88,51 +88,51 @@ struct spear_adc_info { * static inline functions, because of different register offsets * on different SoC variants (SPEAr300 vs SPEAr600 etc). */ -static void spear_adc_set_status(struct spear_adc_info *info, u32 val) +static void spear_adc_set_status(struct spear_adc_state *st, u32 val) { - __raw_writel(val, &info->adc_base_spear6xx->status); + __raw_writel(val, &st->adc_base_spear6xx->status); } -static void spear_adc_set_clk(struct spear_adc_info *info, u32 val) +static void spear_adc_set_clk(struct spear_adc_state *st, u32 val) { u32 clk_high, clk_low, count; - u32 apb_clk = clk_get_rate(info->clk); + u32 apb_clk = clk_get_rate(st->clk); count = (apb_clk + val - 1) / val; clk_low = count / 2; clk_high = count - clk_low; - info->current_clk = apb_clk / count; + st->current_clk = apb_clk / count; __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), - &info->adc_base_spear6xx->clk); + &st->adc_base_spear6xx->clk); } -static void spear_adc_set_ctrl(struct spear_adc_info *info, int n, +static void spear_adc_set_ctrl(struct spear_adc_state *st, int n, u32 val) { - __raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]); + __raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]); } -static u32 spear_adc_get_average(struct spear_adc_info *info) +static u32 spear_adc_get_average(struct spear_adc_state *st) { - if (of_device_is_compatible(info->np, "st,spear600-adc")) { - return __raw_readl(&info->adc_base_spear6xx->average.msb) & + if (of_device_is_compatible(st->np, "st,spear600-adc")) { + return __raw_readl(&st->adc_base_spear6xx->average.msb) & SPEAR_ADC_DATA_MASK; } else { - return __raw_readl(&info->adc_base_spear3xx->average) & + return __raw_readl(&st->adc_base_spear3xx->average) & SPEAR_ADC_DATA_MASK; } } -static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate) +static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) { - if (of_device_is_compatible(info->np, "st,spear600-adc")) { + if (of_device_is_compatible(st->np, "st,spear600-adc")) { __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), - &info->adc_base_spear6xx->scan_rate_lo); + &st->adc_base_spear6xx->scan_rate_lo); __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), - &info->adc_base_spear6xx->scan_rate_hi); + &st->adc_base_spear6xx->scan_rate_hi); } else { - __raw_writel(rate, &info->adc_base_spear3xx->scan_rate); + __raw_writel(rate, &st->adc_base_spear3xx->scan_rate); } } @@ -142,7 +142,7 @@ static int spear_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { - struct spear_adc_info *info = iio_priv(indio_dev); + struct spear_adc_state *st = iio_priv(indio_dev); u32 status; switch (mask) { @@ -150,26 +150,26 @@ static int spear_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | - SPEAR_ADC_STATUS_AVG_SAMPLE(info->avg_samples) | + SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | SPEAR_ADC_STATUS_START_CONVERSION | SPEAR_ADC_STATUS_ADC_ENABLE; - if (info->vref_external == 0) + if (st->vref_external == 0) status |= SPEAR_ADC_STATUS_VREF_INTERNAL; - spear_adc_set_status(info, status); - wait_for_completion(&info->completion); /* set by ISR */ - *val = info->value; + spear_adc_set_status(st, status); + wait_for_completion(&st->completion); /* set by ISR */ + *val = st->value; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = info->vref_external; + *val = st->vref_external; *val2 = SPEAR_ADC_DATA_BITS; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ: - *val = info->current_clk; + *val = st->current_clk; return IIO_VAL_INT; } @@ -182,7 +182,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev, int val2, long mask) { - struct spear_adc_info *info = iio_priv(indio_dev); + struct spear_adc_state *st = iio_priv(indio_dev); int ret = 0; if (mask != IIO_CHAN_INFO_SAMP_FREQ) @@ -197,7 +197,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev, goto out; } - spear_adc_set_clk(info, val); + spear_adc_set_clk(st, val); out: mutex_unlock(&indio_dev->mlock); @@ -226,32 +226,32 @@ static const struct iio_chan_spec spear_adc_iio_channels[] = { static irqreturn_t spear_adc_isr(int irq, void *dev_id) { - struct spear_adc_info *info = (struct spear_adc_info *)dev_id; + struct spear_adc_state *st = (struct spear_adc_state *)dev_id; /* Read value to clear IRQ */ - info->value = spear_adc_get_average(info); - complete(&info->completion); + st->value = spear_adc_get_average(st); + complete(&st->completion); return IRQ_HANDLED; } -static int spear_adc_configure(struct spear_adc_info *info) +static int spear_adc_configure(struct spear_adc_state *st) { int i; /* Reset ADC core */ - spear_adc_set_status(info, 0); - __raw_writel(0, &info->adc_base_spear6xx->clk); + spear_adc_set_status(st, 0); + __raw_writel(0, &st->adc_base_spear6xx->clk); for (i = 0; i < 8; i++) - spear_adc_set_ctrl(info, i, 0); - spear_adc_set_scanrate(info, 0); + spear_adc_set_ctrl(st, i, 0); + spear_adc_set_scanrate(st, 0); - spear_adc_set_clk(info, info->sampling_freq); + spear_adc_set_clk(st, st->sampling_freq); return 0; } -static const struct iio_info spear_adc_iio_info = { +static const struct iio_info spear_adc_info = { .read_raw = &spear_read_raw, .write_raw = &spear_adc_write_raw, .driver_module = THIS_MODULE, @@ -261,40 +261,40 @@ static int spear_adc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct spear_adc_info *info; + struct spear_adc_state *st; struct iio_dev *iodev = NULL; int ret = -ENODEV; int irq; - iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_info)); + iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); if (!iodev) { dev_err(dev, "failed allocating iio device\n"); return -ENOMEM; } - info = iio_priv(iodev); - info->np = np; + st = iio_priv(iodev); + st->np = np; /* * SPEAr600 has a different register layout than other SPEAr SoC's * (e.g. SPEAr3xx). Let's provide two register base addresses * to support multi-arch kernels. */ - info->adc_base_spear6xx = of_iomap(np, 0); - if (!info->adc_base_spear6xx) { + st->adc_base_spear6xx = of_iomap(np, 0); + if (!st->adc_base_spear6xx) { dev_err(dev, "failed mapping memory\n"); return -ENOMEM; } - info->adc_base_spear3xx = - (struct adc_regs_spear3xx __iomem *)info->adc_base_spear6xx; + st->adc_base_spear3xx = + (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; - info->clk = clk_get(dev, NULL); - if (IS_ERR(info->clk)) { + st->clk = clk_get(dev, NULL); + if (IS_ERR(st->clk)) { dev_err(dev, "failed getting clock\n"); goto errout1; } - ret = clk_prepare_enable(info->clk); + ret = clk_prepare_enable(st->clk); if (ret) { dev_err(dev, "failed enabling clock\n"); goto errout2; @@ -308,14 +308,14 @@ static int spear_adc_probe(struct platform_device *pdev) } ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, - info); + st); if (ret < 0) { dev_err(dev, "failed requesting interrupt\n"); goto errout3; } if (of_property_read_u32(np, "sampling-frequency", - &info->sampling_freq)) { + &st->sampling_freq)) { dev_err(dev, "sampling-frequency missing in DT\n"); ret = -EINVAL; goto errout3; @@ -325,23 +325,23 @@ static int spear_adc_probe(struct platform_device *pdev) * Optional avg_samples defaults to 0, resulting in single data * conversion */ - of_property_read_u32(np, "average-samples", &info->avg_samples); + of_property_read_u32(np, "average-samples", &st->avg_samples); /* * Optional vref_external defaults to 0, resulting in internal vref * selection */ - of_property_read_u32(np, "vref-external", &info->vref_external); + of_property_read_u32(np, "vref-external", &st->vref_external); - spear_adc_configure(info); + spear_adc_configure(st); platform_set_drvdata(pdev, iodev); - init_completion(&info->completion); + init_completion(&st->completion); iodev->name = SPEAR_ADC_MOD_NAME; iodev->dev.parent = dev; - iodev->info = &spear_adc_iio_info; + iodev->info = &spear_adc_info; iodev->modes = INDIO_DIRECT_MODE; iodev->channels = spear_adc_iio_channels; iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); @@ -355,23 +355,23 @@ static int spear_adc_probe(struct platform_device *pdev) return 0; errout3: - clk_disable_unprepare(info->clk); + clk_disable_unprepare(st->clk); errout2: - clk_put(info->clk); + clk_put(st->clk); errout1: - iounmap(info->adc_base_spear6xx); + iounmap(st->adc_base_spear6xx); return ret; } static int spear_adc_remove(struct platform_device *pdev) { struct iio_dev *iodev = platform_get_drvdata(pdev); - struct spear_adc_info *info = iio_priv(iodev); + struct spear_adc_state *st = iio_priv(iodev); iio_device_unregister(iodev); - clk_disable_unprepare(info->clk); - clk_put(info->clk); - iounmap(info->adc_base_spear6xx); + clk_disable_unprepare(st->clk); + clk_put(st->clk); + iounmap(st->adc_base_spear6xx); return 0; } -- cgit v1.1 From e90ba52f4dee0e8e96910efe96358b1f9ed0f9d2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear rename iodev -> indio_dev to fit with current convention How we ended up with indio_dev is a mystery, but we have so in the interests of consistency, move this driver over to that convention. Signed-off-by: Jonathan Cameron Acked-by: Hartmut Knaack --- drivers/staging/iio/adc/spear_adc.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 3003e89..52c26a6 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -262,17 +262,17 @@ static int spear_adc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct spear_adc_state *st; - struct iio_dev *iodev = NULL; + struct iio_dev *indio_dev = NULL; int ret = -ENODEV; int irq; - iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); - if (!iodev) { + indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); + if (!indio_dev) { dev_err(dev, "failed allocating iio device\n"); return -ENOMEM; } - st = iio_priv(iodev); + st = iio_priv(indio_dev); st->np = np; /* @@ -335,18 +335,18 @@ static int spear_adc_probe(struct platform_device *pdev) spear_adc_configure(st); - platform_set_drvdata(pdev, iodev); + platform_set_drvdata(pdev, indio_dev); init_completion(&st->completion); - iodev->name = SPEAR_ADC_MOD_NAME; - iodev->dev.parent = dev; - iodev->info = &spear_adc_info; - iodev->modes = INDIO_DIRECT_MODE; - iodev->channels = spear_adc_iio_channels; - iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); + indio_dev->name = SPEAR_ADC_MOD_NAME; + indio_dev->dev.parent = dev; + indio_dev->info = &spear_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = spear_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); - ret = iio_device_register(iodev); + ret = iio_device_register(indio_dev); if (ret) goto errout3; @@ -365,10 +365,10 @@ errout1: static int spear_adc_remove(struct platform_device *pdev) { - struct iio_dev *iodev = platform_get_drvdata(pdev); - struct spear_adc_state *st = iio_priv(iodev); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct spear_adc_state *st = iio_priv(indio_dev); - iio_device_unregister(iodev); + iio_device_unregister(indio_dev); clk_disable_unprepare(st->clk); clk_put(st->clk); iounmap(st->adc_base_spear6xx); -- cgit v1.1 From e20d6090e314fa52f25e4a257de3672aa474122c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 4 May 2014 17:45:00 +0100 Subject: staging:iio:adc:spear rename spear_read_raw to spear_adc_read_raw This brings it inline with all the other prefix usage in the driver. Signed-off-by: Jonathan Cameron Acked-by: Hartmut Knaack --- drivers/staging/iio/adc/spear_adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 52c26a6..c5492ba 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -136,11 +136,11 @@ static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) } } -static int spear_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) +static int spear_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) { struct spear_adc_state *st = iio_priv(indio_dev); u32 status; @@ -252,7 +252,7 @@ static int spear_adc_configure(struct spear_adc_state *st) } static const struct iio_info spear_adc_info = { - .read_raw = &spear_read_raw, + .read_raw = &spear_adc_read_raw, .write_raw = &spear_adc_write_raw, .driver_module = THIS_MODULE, }; -- cgit v1.1 From 9ef080ec0c5e9cddf68e73a70438a2a7916b595a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 4 Aug 2014 14:24:00 +0100 Subject: iio: adc: Fix exynos_adc dependencies EXYNOS_ADC shouldn't only depend on OF. It is useless on architectures other than Exynos so it should depend on ARCH_EXYNOS (which implies OF.) Signed-off-by: Jean Delvare Cc: Jonathan Cameron Cc: Kukjin Kim Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 1dffa2d..5572c50 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -118,7 +118,7 @@ config AT91_ADC config EXYNOS_ADC bool "Exynos ADC driver support" - depends on OF + depends on ARCH_EXYNOS || (OF && COMPILE_TEST) help Core support for the ADC block found in the Samsung EXYNOS series of SoCs for drivers such as the touchscreen and hwmon to use to share -- cgit v1.1 From 913423409df02fe6706ee81d9ac5c31f166c3d6c Mon Sep 17 00:00:00 2001 From: Michael Welling Date: Sat, 4 Oct 2014 03:26:00 +0100 Subject: Staging:iio:tsl2583 Removes unwanted space before semicolon Signed-off-by: Michael Welling Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index f8c6595..9d39387 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -211,7 +211,7 @@ static int taos_get_lux(struct iio_dev *indio_dev) if (chip->taos_chip_status != TSL258X_CHIP_WORKING) { /* device is not enabled */ dev_err(&chip->client->dev, "taos_get_lux device is not enabled\n"); - ret = -EBUSY ; + ret = -EBUSY; goto out_unlock; } -- cgit v1.1 From cf0d0739c0d1f1ae6178c187db6550b96dfa2019 Mon Sep 17 00:00:00 2001 From: Michael Welling Date: Sat, 4 Oct 2014 03:26:00 +0100 Subject: Staging:iio:tsl2583 Remove quoted string split across lines warnings Signed-off-by: Michael Welling Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2583.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index 9d39387..8d46c92 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -165,8 +165,9 @@ taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) /* select register to write */ ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg)); if (ret < 0) { - dev_err(&client->dev, "taos_i2c_read failed to write" - " register %x\n", reg); + dev_err(&client->dev, + "taos_i2c_read failed to write register %x\n", + reg); return ret; } /* read the data */ @@ -231,8 +232,9 @@ static int taos_get_lux(struct iio_dev *indio_dev) int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i); ret = taos_i2c_read(chip->client, reg, &buf[i], 1); if (ret < 0) { - dev_err(&chip->client->dev, "taos_get_lux failed to read" - " register %x\n", reg); + dev_err(&chip->client->dev, + "taos_get_lux failed to read register %x\n", + reg); goto out_unlock; } } @@ -809,9 +811,7 @@ static int taos_probe(struct i2c_client *clientp, if (!i2c_check_functionality(clientp->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&clientp->dev, - "taos_probe() - i2c smbus byte data " - "functions unsupported\n"); + dev_err(&clientp->dev, "taos_probe() - i2c smbus byte data func unsupported\n"); return -EOPNOTSUPP; } @@ -830,30 +830,32 @@ static int taos_probe(struct i2c_client *clientp, ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " - "reg failed in taos_probe(), err = %d\n", ret); + dev_err(&clientp->dev, + "i2c_smbus_write_byte to cmd reg failed in taos_probe(), err = %d\n", + ret); return ret; } ret = i2c_smbus_read_byte(clientp); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_read_byte from " - "reg failed in taos_probe(), err = %d\n", ret); - + dev_err(&clientp->dev, + "i2c_smbus_read_byte from reg failed in taos_probe(), err = %d\n", + ret); return ret; } buf[i] = ret; } if (!taos_tsl258x_device(buf)) { - dev_info(&clientp->dev, "i2c device found but does not match " - "expected id in taos_probe()\n"); + dev_info(&clientp->dev, + "i2c device found but does not match expected id in taos_probe()\n"); return -EINVAL; } ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); if (ret < 0) { - dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " - "failed in taos_probe(), err = %d\n", ret); + dev_err(&clientp->dev, + "i2c_smbus_write_byte() to cmd reg failed in taos_probe(), err = %d\n", + ret); return ret; } -- cgit v1.1 From e193385bf4fa1bdbafcc12eaea4f0e718aeae858 Mon Sep 17 00:00:00 2001 From: Michael Welling Date: Sat, 4 Oct 2014 03:26:00 +0100 Subject: Staging:iio:tsl2583 Switch from msleep to usleep range per timers-howto.txt Signed-off-by: Michael Welling Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index 8d46c92..de3c9d8 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -451,7 +451,7 @@ static int taos_chip_on(struct iio_dev *indio_dev) } } - msleep(3); + usleep_range(3000, 3500); /* NOW enable the ADC * initialize the desired mode of operation */ utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL; -- cgit v1.1 From e3c5be2bdae553ddefacc636496f2df21aee31ee Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 22 Apr 2014 12:23:00 +0100 Subject: staging: iio: Fix typo in iio Correct spelling typo in comment within staging/iio Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 2 +- drivers/staging/iio/adc/ad7606.h | 4 ++-- drivers/staging/iio/adc/ad7816.c | 2 +- drivers/staging/iio/addac/adt7316.c | 4 ++-- drivers/staging/iio/cdc/ad7152.c | 2 +- drivers/staging/iio/cdc/ad7746.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index bcbf610..16a8b14 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -102,7 +102,7 @@ enum { }; /** - * struct ad799x_chip_info - chip specifc information + * struct ad799x_chip_info - chip specific information * @channel: channel specification * @num_channels: number of channels * @monitor_mode: whether the chip supports monitor interrupts diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 93c7299..ec89d05 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -14,7 +14,7 @@ */ /** - * struct ad7606_platform_data - platform/board specifc information + * struct ad7606_platform_data - platform/board specific information * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64} * @default_range: default range +/-{5000, 10000} mVolt * @gpio_convst: number of gpio connected to the CONVST pin @@ -41,7 +41,7 @@ struct ad7606_platform_data { }; /** - * struct ad7606_chip_info - chip specifc information + * struct ad7606_chip_info - chip specific information * @name: identification string for chip * @int_vref_mv: the internal reference voltage * @channels: channel specification diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 2369cf2..158d770 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -40,7 +40,7 @@ /* - * struct ad7816_chip_info - chip specifc information + * struct ad7816_chip_info - chip specific information */ struct ad7816_chip_info { diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 16a8201..6806d42 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -172,7 +172,7 @@ #define ID_ADT75XX 0x10 /* - * struct adt7316_chip_info - chip specifc information + * struct adt7316_chip_info - chip specific information */ struct adt7316_chip_info { @@ -208,7 +208,7 @@ struct adt7316_chip_info { (ADT7316_TEMP_INT_MASK) /* - * struct adt7316_chip_info - chip specifc information + * struct adt7316_chip_info - chip specific information */ struct adt7316_limit_regs { diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index f2c309d..87110d9 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -78,7 +78,7 @@ enum { }; /* - * struct ad7152_chip_info - chip specifc information + * struct ad7152_chip_info - chip specific information */ struct ad7152_chip_info { diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index cbb1588..e6e9eaa 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -91,7 +91,7 @@ #define AD7746_CAPDAC_DACP(x) ((x) & 0x7F) /* - * struct ad7746_chip_info - chip specifc information + * struct ad7746_chip_info - chip specific information */ struct ad7746_chip_info { -- cgit v1.1 From 4f544ced19b3d300ac11414b68a676a2c42f6d06 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 13 Apr 2014 20:08:00 +0100 Subject: iio: st_sensors: announce registered sensors It is pretty helpful to know already from dmesg that a certain device is successfully registered, instead of having to browse sysfs to see if it's actually there. Cc: Lee Jones Cc: Denis CIOCCA Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 3 +++ drivers/iio/gyro/st_gyro_core.c | 3 +++ drivers/iio/magnetometer/st_magn_core.c | 3 +++ drivers/iio/pressure/st_pressure_core.c | 3 +++ 4 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 38caedc..4e06fcf 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -496,6 +496,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev, if (err) goto st_accel_device_register_error; + dev_info(&indio_dev->dev, "registered accelerometer %s\n", + indio_dev->name); + return 0; st_accel_device_register_error: diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index a8e174a..bc71f4d 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -344,6 +344,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, if (err) goto st_gyro_device_register_error; + dev_info(&indio_dev->dev, "registered gyroscope %s\n", + indio_dev->name); + return 0; st_gyro_device_register_error: diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 52bbcfa..8e33a76 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -387,6 +387,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev, if (err) goto st_magn_device_register_error; + dev_info(&indio_dev->dev, "registered magnetometer %s\n", + indio_dev->name); + return 0; st_magn_device_register_error: diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 7418768..013becb 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -474,6 +474,9 @@ int st_press_common_probe(struct iio_dev *indio_dev, if (err) goto st_press_device_register_error; + dev_info(&indio_dev->dev, "registered pressure sensor %s\n", + indio_dev->name); + return err; st_press_device_register_error: -- cgit v1.1 From ea7e586bdd331fd6fba2b6f9fd3777928c2814d8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 13 Apr 2014 20:08:00 +0100 Subject: iio: st_sensors: move regulator retrieveal to core Currently the pressure sensor has code to retrieve and enable two regulators for Vdd and Vdd IO, but actually these voltage inputs are found on all of these ST sensors, so move the regulator handling to the core and make sure all the ST sensors call these functions on probe() and remove() to enable/disable power. Here also mover over to obtaining the regulator from the *parent* device of the IIO device, as the IIO device is created on-the-fly in this very subsystem it very unlikely evert have any regulators attached to it whatsoever. It is much more likely that the parent is a platform device, possibly instantiated from a device tree, which in turn have Vdd and Vdd IO supplied assigned to it. Cc: Lee Jones Cc: Denis CIOCCA Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 4 +++ drivers/iio/common/st_sensors/st_sensors_core.c | 37 +++++++++++++++++++++++ drivers/iio/gyro/st_gyro_core.c | 4 +++ drivers/iio/magnetometer/st_magn_core.c | 4 +++ drivers/iio/pressure/st_pressure_core.c | 39 ++----------------------- 5 files changed, 51 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 4e06fcf..a2abf7c 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -459,6 +459,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors), st_accel_sensors); if (err < 0) @@ -515,6 +517,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (adata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 7ba1ef2..e8b932f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -198,6 +199,42 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); +void st_sensors_power_enable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + int err; + + /* Regulators not mandatory, but if requested we should enable them. */ + pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); + if (!IS_ERR(pdata->vdd)) { + err = regulator_enable(pdata->vdd); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd supply\n"); + } + + pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); + if (!IS_ERR(pdata->vdd_io)) { + err = regulator_enable(pdata->vdd_io); + if (err != 0) + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd_IO supply\n"); + } +} +EXPORT_SYMBOL(st_sensors_power_enable); + +void st_sensors_power_disable(struct iio_dev *indio_dev) +{ + struct st_sensor_data *pdata = iio_priv(indio_dev); + + if (!IS_ERR(pdata->vdd)) + regulator_disable(pdata->vdd); + + if (!IS_ERR(pdata->vdd_io)) + regulator_disable(pdata->vdd_io); +} +EXPORT_SYMBOL(st_sensors_power_disable); + static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) { diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index bc71f4d..ed74a90 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -311,6 +311,8 @@ int st_gyro_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors); if (err < 0) @@ -363,6 +365,8 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (gdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8e33a76..240a21d 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -355,6 +355,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; + st_sensors_power_enable(indio_dev); + err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors), st_magn_sensors); if (err < 0) @@ -406,6 +408,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); + st_sensors_power_disable(indio_dev); + iio_device_unregister(indio_dev); if (mdata->get_irq_data_ready(indio_dev) > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 013becb..cd7e01f 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -387,40 +386,6 @@ static const struct iio_trigger_ops st_press_trigger_ops = { #define ST_PRESS_TRIGGER_OPS NULL #endif -static void st_press_power_enable(struct iio_dev *indio_dev) -{ - struct st_sensor_data *pdata = iio_priv(indio_dev); - int err; - - /* Regulators not mandatory, but if requested we should enable them. */ - pdata->vdd = devm_regulator_get_optional(&indio_dev->dev, "vdd"); - if (!IS_ERR(pdata->vdd)) { - err = regulator_enable(pdata->vdd); - if (err != 0) - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd supply\n"); - } - - pdata->vdd_io = devm_regulator_get_optional(&indio_dev->dev, "vddio"); - if (!IS_ERR(pdata->vdd_io)) { - err = regulator_enable(pdata->vdd_io); - if (err != 0) - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd_IO supply\n"); - } -} - -static void st_press_power_disable(struct iio_dev *indio_dev) -{ - struct st_sensor_data *pdata = iio_priv(indio_dev); - - if (!IS_ERR(pdata->vdd)) - regulator_disable(pdata->vdd); - - if (!IS_ERR(pdata->vdd_io)) - regulator_disable(pdata->vdd_io); -} - int st_press_common_probe(struct iio_dev *indio_dev, struct st_sensors_platform_data *plat_data) { @@ -431,7 +396,7 @@ int st_press_common_probe(struct iio_dev *indio_dev, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - st_press_power_enable(indio_dev); + st_sensors_power_enable(indio_dev); err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_press_sensors), @@ -493,7 +458,7 @@ void st_press_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); - st_press_power_disable(indio_dev); + st_sensors_power_disable(indio_dev); iio_device_unregister(indio_dev); if (pdata->get_irq_data_ready(indio_dev) > 0) -- cgit v1.1