From 8a9f645fc15b4bb49a1c8133df9db0ccd67e3f76 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Thu, 10 Jan 2013 17:29:00 +0000 Subject: [PATCH 01/40] iio: fix Kconfig for max1363 ERROR: "iio_triggered_buffer_setup" [drivers/iio/adc/max1363.ko] undefined! ERROR: "iio_triggered_buffer_cleanup" [drivers/iio/adc/max1363.ko] undefined! add select IIO_TRIGGERED_BUFFER IIO_TRIGGERED_BUFFER in turn selects IIO_TRIGGER and IIO_KFIFO_BUF, so drop those MAX1363_RING_BUFFER is not used anymore Signed-off-by: Peter Meerwald Reported-by: Fengguang Wu Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index fe822a14d130..e372257a8494 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -100,10 +100,8 @@ config LP8788_ADC config MAX1363 tristate "Maxim max1363 ADC driver" depends on I2C - select IIO_TRIGGER - select MAX1363_RING_BUFFER select IIO_BUFFER - select IIO_KFIFO_BUF + select IIO_TRIGGERED_BUFFER help Say yes here to build support for many Maxim i2c analog to digital converters (ADC). (max1361, max1362, max1363, max1364, max1036, From 2b4ff03895e4451719400e9ac50980b9d14af37d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 11 Jan 2013 10:49:00 +0000 Subject: [PATCH 02/40] staging:iio:gyro: Remove stale Makefile entry Commit a301d425e ("staging:iio:gyro remove adis16251 driver as now supported by adis16260 driver") removed the adis16251, but left its Makefile entry intact. This patch removes the unused Makefile entry. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 1303569e5c8a..79bef4ef7a54 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -14,8 +14,5 @@ obj-$(CONFIG_ADIS16130) += adis16130.o adis16260-y := adis16260_core.o obj-$(CONFIG_ADIS16260) += adis16260.o -adis16251-y := adis16251_core.o -obj-$(CONFIG_ADIS16251) += adis16251.o - adxrs450-y := adxrs450_core.o obj-$(CONFIG_ADXRS450) += adxrs450.o From 06ddd353f5c8678238d519dcecf9d557e5e1f7a6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 11 Jan 2013 23:35:00 +0000 Subject: [PATCH 03/40] iio: mxs: Implement support for touchscreen This patch implements support for sampling of a touchscreen into the MXS LRADC driver. The LRADC block allows configuring some of it's channels into special mode where they either output the drive voltage or sample it, allowing it to operate a 4-wire or 5-wire resistive touchscreen. In case the touchscreen mode is enabled, the LRADC slot #7 is reserved for touchscreen only, therefore it is not possible to sample 8 LRADC channels at time, but only 7 channels. The touchscreen controller is configured such that the PENDOWN event disables touchscreen interrupts and triggers execution of worker thread, which then polls the touchscreen controller for X, Y and Pressure values. This reduces the overhead of interrupt-driven operation. Upon the PENUP event, the worker thread re-enables the PENDOWN detection interrupt and exits. Signed-off-by: Marek Vasut Acked-by: Dmitry Torokhov Signed-off-by: Jonathan Cameron --- .../bindings/staging/iio/adc/mxs-lradc.txt | 6 + drivers/staging/iio/adc/mxs-lradc.c | 466 +++++++++++++++++- 2 files changed, 451 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt index 801d58cb6d4d..46882058b59b 100644 --- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -5,6 +5,12 @@ Required properties: - reg: Address and length of the register set for the device - interrupts: Should contain the LRADC interrupts +Optional properties: +- fsl,lradc-touchscreen-wires: Number of wires used to connect the touchscreen + to LRADC. Valid value is either 4 or 5. If this + property is not present, then the touchscreen is + disabled. + Examples: lradc@80050000 { diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index eca07045f4de..e4728712a1ad 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -59,6 +61,21 @@ #define LRADC_DELAY_TIMER_PER 200 #define LRADC_DELAY_TIMER_LOOP 5 +/* + * Once the pen touches the touchscreen, the touchscreen switches from + * IRQ-driven mode to polling mode to prevent interrupt storm. The polling + * is realized by worker thread, which is called every 20 or so milliseconds. + * This gives the touchscreen enough fluence and does not strain the system + * too much. + */ +#define LRADC_TS_SAMPLE_DELAY_MS 5 + +/* + * The LRADC reads the following amount of samples from each touchscreen + * channel and the driver then computes avarage of these. + */ +#define LRADC_TS_SAMPLE_AMOUNT 4 + static const char * const mxs_lradc_irq_name[] = { "mxs-lradc-touchscreen", "mxs-lradc-thresh0", @@ -75,6 +92,12 @@ static const char * const mxs_lradc_irq_name[] = { "mxs-lradc-button1", }; +enum mxs_lradc_ts { + MXS_LRADC_TOUCHSCREEN_NONE = 0, + MXS_LRADC_TOUCHSCREEN_4WIRE, + MXS_LRADC_TOUCHSCREEN_5WIRE, +}; + struct mxs_lradc { struct device *dev; void __iomem *base; @@ -86,21 +109,69 @@ struct mxs_lradc { struct mutex lock; struct completion completion; + + /* + * Touchscreen LRADC channels receives a private slot in the CTRL4 + * register, the slot #7. Therefore only 7 slots instead of 8 in the + * CTRL4 register can be mapped to LRADC channels when using the + * touchscreen. + * + * Furthermore, certain LRADC channels are shared between touchscreen + * and/or touch-buttons and generic LRADC block. Therefore when using + * either of these, these channels are not available for the regular + * sampling. The shared channels are as follows: + * + * CH0 -- Touch button #0 + * CH1 -- Touch button #1 + * CH2 -- Touch screen XPUL + * CH3 -- Touch screen YPLL + * CH4 -- Touch screen XNUL + * CH5 -- Touch screen YNLR + * CH6 -- Touch screen WIPER (5-wire only) + * + * The bitfields below represents which parts of the LRADC block are + * switched into special mode of operation. These channels can not + * be sampled as regular LRADC channels. The driver will refuse any + * attempt to sample these channels. + */ +#define CHAN_MASK_TOUCHBUTTON (0x3 << 0) +#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 2) +#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 2) + enum mxs_lradc_ts use_touchscreen; + bool stop_touchscreen; + bool use_touchbutton; + + struct input_dev *ts_input; + struct work_struct ts_work; }; #define LRADC_CTRL0 0x00 -#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23) -#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22) +#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23) +#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22) +#define LRADC_CTRL0_YNNSW /* YM */ (1 << 21) +#define LRADC_CTRL0_YPNSW /* YP */ (1 << 20) +#define LRADC_CTRL0_YPPSW /* YP */ (1 << 19) +#define LRADC_CTRL0_XNNSW /* XM */ (1 << 18) +#define LRADC_CTRL0_XNPSW /* XM */ (1 << 17) +#define LRADC_CTRL0_XPPSW /* XP */ (1 << 16) +#define LRADC_CTRL0_PLATE_MASK (0x3f << 16) #define LRADC_CTRL1 0x10 -#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n)) -#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_TOUCH_DETECT_IRQ_EN (1 << 24) #define LRADC_CTRL1_LRADC_IRQ_EN(n) (1 << ((n) + 16)) #define LRADC_CTRL1_LRADC_IRQ_EN_MASK (0x1fff << 16) +#define LRADC_CTRL1_LRADC_IRQ_EN_OFFSET 16 +#define LRADC_CTRL1_TOUCH_DETECT_IRQ (1 << 8) +#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n)) +#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_LRADC_IRQ_OFFSET 0 #define LRADC_CTRL2 0x20 #define LRADC_CTRL2_TEMPSENSE_PWD (1 << 15) +#define LRADC_STATUS 0x40 +#define LRADC_STATUS_TOUCH_DETECT_RAW (1 << 0) + #define LRADC_CH(n) (0x50 + (0x10 * (n))) #define LRADC_CH_ACCUMULATE (1 << 29) #define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24) @@ -132,6 +203,7 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, { struct mxs_lradc *lradc = iio_priv(iio_dev); int ret; + unsigned long mask; if (m != IIO_CHAN_INFO_RAW) return -EINVAL; @@ -140,6 +212,12 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, if (chan->channel > LRADC_MAX_TOTAL_CHANS) return -EINVAL; + /* Validate the channel if it doesn't intersect with reserved chans. */ + bitmap_set(&mask, chan->channel, 1); + ret = iio_validate_scan_mask_onehot(iio_dev, &mask); + if (ret) + return -EINVAL; + /* * See if there is no buffered operation in progess. If there is, simply * bail out. This can be improved to support both buffered and raw IO at @@ -161,7 +239,11 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - writel(chan->channel, lradc->base + LRADC_CTRL4); + /* Clean the slot's previous content, then set new one. */ + writel(LRADC_CTRL4_LRADCSELECT_MASK(0), + lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); + writel(chan->channel, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); + writel(0, lradc->base + LRADC_CH(0)); /* Enable the IRQ and start sampling the channel. */ @@ -194,6 +276,269 @@ static const struct iio_info mxs_lradc_iio_info = { .read_raw = mxs_lradc_read_raw, }; +/* + * Touchscreen handling + */ +enum lradc_ts_plate { + LRADC_SAMPLE_X, + LRADC_SAMPLE_Y, + LRADC_SAMPLE_PRESSURE, +}; + +static int mxs_lradc_ts_touched(struct mxs_lradc *lradc) +{ + uint32_t reg; + + /* Enable touch detection. */ + writel(LRADC_CTRL0_PLATE_MASK, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + msleep(LRADC_TS_SAMPLE_DELAY_MS); + + reg = readl(lradc->base + LRADC_STATUS); + + return reg & LRADC_STATUS_TOUCH_DETECT_RAW; +} + +static int32_t mxs_lradc_ts_sample(struct mxs_lradc *lradc, + enum lradc_ts_plate plate, int change) +{ + unsigned long delay, jiff; + uint32_t reg, ctrl0 = 0, chan = 0; + /* The touchscreen always uses CTRL4 slot #7. */ + const uint8_t slot = 7; + uint32_t val; + + /* + * There are three correct configurations of the controller sampling + * the touchscreen, each of these configuration provides different + * information from the touchscreen. + * + * The following table describes the sampling configurations: + * +-------------+-------+-------+-------+ + * | Wire \ Axis | X | Y | Z | + * +---------------------+-------+-------+ + * | X+ (CH2) | HI | TS | TS | + * +-------------+-------+-------+-------+ + * | X- (CH4) | LO | SH | HI | + * +-------------+-------+-------+-------+ + * | Y+ (CH3) | SH | HI | HI | + * +-------------+-------+-------+-------+ + * | Y- (CH5) | TS | LO | SH | + * +-------------+-------+-------+-------+ + * + * HI ... strong '1' ; LO ... strong '0' + * SH ... sample here ; TS ... tri-state + * + * There are a few other ways of obtaining the Z coordinate + * (aka. pressure), but the one in the table seems to be the + * most reliable one. + */ + switch (plate) { + case LRADC_SAMPLE_X: + ctrl0 = LRADC_CTRL0_XPPSW | LRADC_CTRL0_XNNSW; + chan = 3; + break; + case LRADC_SAMPLE_Y: + ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_YNNSW; + chan = 4; + break; + case LRADC_SAMPLE_PRESSURE: + ctrl0 = LRADC_CTRL0_YPPSW | LRADC_CTRL0_XNNSW; + chan = 5; + break; + } + + if (change) { + writel(LRADC_CTRL0_PLATE_MASK, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + writel(ctrl0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + writel(LRADC_CTRL4_LRADCSELECT_MASK(slot), + lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); + writel(chan << LRADC_CTRL4_LRADCSELECT_OFFSET(slot), + lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); + } + + writel(0xffffffff, lradc->base + LRADC_CH(slot) + STMP_OFFSET_REG_CLR); + writel(1 << slot, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + delay = jiffies + msecs_to_jiffies(LRADC_TS_SAMPLE_DELAY_MS); + do { + jiff = jiffies; + reg = readl_relaxed(lradc->base + LRADC_CTRL1); + if (reg & LRADC_CTRL1_LRADC_IRQ(slot)) + break; + } while (time_before(jiff, delay)); + + writel(LRADC_CTRL1_LRADC_IRQ(slot), + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + if (time_after_eq(jiff, delay)) + return -ETIMEDOUT; + + val = readl(lradc->base + LRADC_CH(slot)); + val &= LRADC_CH_VALUE_MASK; + + return val; +} + +static int32_t mxs_lradc_ts_sample_filter(struct mxs_lradc *lradc, + enum lradc_ts_plate plate) +{ + int32_t val, tot = 0; + int i; + + val = mxs_lradc_ts_sample(lradc, plate, 1); + + /* Delay a bit so the touchscreen is stable. */ + mdelay(2); + + for (i = 0; i < LRADC_TS_SAMPLE_AMOUNT; i++) { + val = mxs_lradc_ts_sample(lradc, plate, 0); + tot += val; + } + + return tot / LRADC_TS_SAMPLE_AMOUNT; +} + +static void mxs_lradc_ts_work(struct work_struct *ts_work) +{ + struct mxs_lradc *lradc = container_of(ts_work, + struct mxs_lradc, ts_work); + int val_x, val_y, val_p; + bool valid = false; + + while (mxs_lradc_ts_touched(lradc)) { + /* Disable touch detector so we can sample the touchscreen. */ + writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + if (likely(valid)) { + input_report_abs(lradc->ts_input, ABS_X, val_x); + input_report_abs(lradc->ts_input, ABS_Y, val_y); + input_report_abs(lradc->ts_input, ABS_PRESSURE, val_p); + input_report_key(lradc->ts_input, BTN_TOUCH, 1); + input_sync(lradc->ts_input); + } + + valid = false; + + val_x = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_X); + if (val_x < 0) + continue; + val_y = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_Y); + if (val_y < 0) + continue; + val_p = mxs_lradc_ts_sample_filter(lradc, LRADC_SAMPLE_PRESSURE); + if (val_p < 0) + continue; + + valid = true; + } + + input_report_abs(lradc->ts_input, ABS_PRESSURE, 0); + input_report_key(lradc->ts_input, BTN_TOUCH, 0); + input_sync(lradc->ts_input); + + /* Do not restart the TS IRQ if the driver is shutting down. */ + if (lradc->stop_touchscreen) + return; + + /* Restart the touchscreen interrupts. */ + writel(LRADC_CTRL1_TOUCH_DETECT_IRQ, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); +} + +static int mxs_lradc_ts_open(struct input_dev *dev) +{ + struct mxs_lradc *lradc = input_get_drvdata(dev); + + /* The touchscreen is starting. */ + lradc->stop_touchscreen = false; + + /* Enable the touch-detect circuitry. */ + writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + /* Enable the touch-detect IRQ. */ + writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + + return 0; +} + +static void mxs_lradc_ts_close(struct input_dev *dev) +{ + struct mxs_lradc *lradc = input_get_drvdata(dev); + + /* Indicate the touchscreen is stopping. */ + lradc->stop_touchscreen = true; + mb(); + + /* Wait until touchscreen thread finishes any possible remnants. */ + cancel_work_sync(&lradc->ts_work); + + /* Disable touchscreen touch-detect IRQ. */ + writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + /* Power-down touchscreen touch-detect circuitry. */ + writel(LRADC_CTRL0_TOUCH_DETECT_ENABLE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); +} + +static int mxs_lradc_ts_register(struct mxs_lradc *lradc) +{ + struct input_dev *input; + struct device *dev = lradc->dev; + int ret; + + if (!lradc->use_touchscreen) + return 0; + + input = input_allocate_device(); + if (!input) { + dev_err(dev, "Failed to allocate TS device!\n"); + return -ENOMEM; + } + + input->name = DRIVER_NAME; + input->id.bustype = BUS_HOST; + input->dev.parent = dev; + input->open = mxs_lradc_ts_open; + input->close = mxs_lradc_ts_close; + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_X, 0, LRADC_CH_VALUE_MASK, 0, 0); + input_set_abs_params(input, ABS_Y, 0, LRADC_CH_VALUE_MASK, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_CH_VALUE_MASK, 0, 0); + + lradc->ts_input = input; + input_set_drvdata(input, lradc); + ret = input_register_device(input); + if (ret) + input_free_device(lradc->ts_input); + + return ret; +} + +static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc) +{ + if (!lradc->use_touchscreen) + return; + + cancel_work_sync(&lradc->ts_work); + + input_unregister_device(lradc->ts_input); +} + /* * IRQ Handling */ @@ -202,14 +547,24 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) struct iio_dev *iio = data; struct mxs_lradc *lradc = iio_priv(iio); unsigned long reg = readl(lradc->base + LRADC_CTRL1); + const uint32_t ts_irq_mask = + LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | + LRADC_CTRL1_TOUCH_DETECT_IRQ; if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK)) return IRQ_NONE; /* - * Touchscreen IRQ handling code shall probably have priority - * and therefore shall be placed here. + * Touchscreen IRQ handling code has priority and therefore + * is placed here. In case touchscreen IRQ arrives, disable + * it ASAP */ + if (reg & LRADC_CTRL1_TOUCH_DETECT_IRQ) { + writel(ts_irq_mask, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + if (!lradc->stop_touchscreen) + schedule_work(&lradc->ts_work); + } if (iio_buffer_enabled(iio)) iio_trigger_poll(iio->trig, iio_get_time_ns()); @@ -305,8 +660,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) { struct mxs_lradc *lradc = iio_priv(iio); struct iio_buffer *buffer = iio->buffer; - int ret = 0, chan, ofs = 0, enable = 0; - uint32_t ctrl4 = 0; + int ret = 0, chan, ofs = 0; + unsigned long enable = 0; + uint32_t ctrl4_set = 0; + uint32_t ctrl4_clr = 0; uint32_t ctrl1_irq = 0; const uint32_t chan_value = LRADC_CH_ACCUMULATE | ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); @@ -338,17 +695,20 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) { - ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); + ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); + ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs); ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs); writel(chan_value, lradc->base + LRADC_CH(ofs)); - enable |= 1 << ofs; + bitmap_set(&enable, ofs, 1); ofs++; } writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); - writel(ctrl4, lradc->base + LRADC_CTRL4); + writel(ctrl4_clr, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR); + writel(ctrl4_set, lradc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET); + writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET, @@ -383,9 +743,33 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, const unsigned long *mask) { - const int mw = bitmap_weight(mask, iio->masklength); - - return mw <= LRADC_MAX_MAPPED_CHANS; + struct mxs_lradc *lradc = iio_priv(iio); + const int len = iio->masklength; + const int map_chans = bitmap_weight(mask, len); + int rsvd_chans = 0; + unsigned long rsvd_mask = 0; + + if (lradc->use_touchbutton) + rsvd_mask |= CHAN_MASK_TOUCHBUTTON; + if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_4WIRE) + rsvd_mask |= CHAN_MASK_TOUCHSCREEN_4WIRE; + if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE) + rsvd_mask |= CHAN_MASK_TOUCHSCREEN_5WIRE; + + if (lradc->use_touchbutton) + rsvd_chans++; + if (lradc->use_touchscreen) + rsvd_chans++; + + /* Test for attempts to map channels with special mode of operation. */ + if (bitmap_intersects(mask, &rsvd_mask, len)) + return false; + + /* Test for attempts to map more channels then available slots. */ + if (map_chans + rsvd_chans > LRADC_MAX_MAPPED_CHANS) + return false; + + return true; } static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { @@ -434,15 +818,29 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { static void mxs_lradc_hw_init(struct mxs_lradc *lradc) { - int i; - const uint32_t cfg = + /* The ADC always uses DELAY CHANNEL 0. */ + const uint32_t adc_cfg = + (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) | (LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET); stmp_reset_block(lradc->base); - for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) - writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)), - lradc->base + LRADC_DELAY(i)); + /* Configure DELAY CHANNEL 0 for generic ADC sampling. */ + writel(adc_cfg, lradc->base + LRADC_DELAY(0)); + + /* Disable remaining DELAY CHANNELs */ + writel(0, lradc->base + LRADC_DELAY(1)); + writel(0, lradc->base + LRADC_DELAY(2)); + writel(0, lradc->base + LRADC_DELAY(3)); + + /* Configure the touchscreen type */ + writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE) { + writel(LRADC_CTRL0_TOUCH_SCREEN_TYPE, + lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + } /* Start internal temperature sensing. */ writel(0, lradc->base + LRADC_CTRL2); @@ -462,9 +860,11 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) static int mxs_lradc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; struct mxs_lradc *lradc; struct iio_dev *iio; struct resource *iores; + uint32_t ts_wires = 0; int ret = 0; int i; @@ -486,6 +886,21 @@ static int mxs_lradc_probe(struct platform_device *pdev) goto err_addr; } + INIT_WORK(&lradc->ts_work, mxs_lradc_ts_work); + + /* Check if touchscreen is enabled in DT. */ + ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires", + &ts_wires); + if (ret) + dev_info(dev, "Touchscreen not enabled.\n"); + else if (ts_wires == 4) + lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_4WIRE; + else if (ts_wires == 5) + lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_5WIRE; + else + dev_warn(dev, "Unsupported number of touchscreen wires (%d)\n", + ts_wires); + /* Grab all IRQ sources */ for (i = 0; i < 13; i++) { lradc->irq[i] = platform_get_irq(pdev, i); @@ -523,11 +938,16 @@ static int mxs_lradc_probe(struct platform_device *pdev) if (ret) goto err_trig; + /* Register the touchscreen input device. */ + ret = mxs_lradc_ts_register(lradc); + if (ret) + goto err_dev; + /* Register IIO device. */ ret = iio_device_register(iio); if (ret) { dev_err(dev, "Failed to register IIO device\n"); - goto err_dev; + goto err_ts; } /* Configure the hardware. */ @@ -535,6 +955,8 @@ static int mxs_lradc_probe(struct platform_device *pdev) return 0; +err_ts: + mxs_lradc_ts_unregister(lradc); err_dev: mxs_lradc_trigger_remove(iio); err_trig: @@ -549,6 +971,8 @@ static int mxs_lradc_remove(struct platform_device *pdev) struct iio_dev *iio = platform_get_drvdata(pdev); struct mxs_lradc *lradc = iio_priv(iio); + mxs_lradc_ts_unregister(lradc); + mxs_lradc_hw_stop(lradc); iio_device_unregister(iio); From 3f6a0bad61e34c648fd08ff8dcbfdd58148963d2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 10 Jan 2013 16:18:00 +0000 Subject: [PATCH 04/40] staging:iio:tsl2x7x: Use iio_str_to_fixedpoint instead of open-coding it The tsl2x7x driver has a copy'n'pasted version of the iio_str_to_fixedpoint() function from the IIO core. Replace this custom copy and use iio_str_to_fixedpoint instead. The patch also introduces a slight functional change in that it makes sure that in case of a parsing error the error is reported back to userspace instead of silently ignoring it. Signed-off-by: Lars-Peter Clausen Acked-by: Jon Brenner Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2x7x_core.c | 78 ++++-------------------- 1 file changed, 12 insertions(+), 66 deletions(-) diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 9e50fbbadf9d..a58731e70bb9 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -291,59 +291,6 @@ static const u8 device_channel_config[] = { ALSPRX2 }; -/** - * tsl2x7x_parse_buffer() - parse a decimal result from a buffer. - * @*buf: pointer to char buffer to parse - * @*result: pointer to buffer to contain - * resulting interger / decimal as ints. - * - */ -static int -tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result) -{ - int integer = 0, fract = 0, fract_mult = 100000; - bool integer_part = true, negative = false; - - if (buf[0] == '-') { - negative = true; - buf++; - } - - while (*buf) { - if ('0' <= *buf && *buf <= '9') { - if (integer_part) - integer = integer*10 + *buf - '0'; - else { - fract += fract_mult*(*buf - '0'); - if (fract_mult == 1) - break; - fract_mult /= 10; - } - } else if (*buf == '\n') { - if (*(buf + 1) == '\0') - break; - else - return -EINVAL; - } else if (*buf == '.') { - integer_part = false; - } else { - return -EINVAL; - } - buf++; - } - if (negative) { - if (integer) - integer = -integer; - else - fract = -fract; - } - - result->integer = integer; - result->fract = fract; - - return 0; -} - /** * tsl2x7x_i2c_read() - Read a byte from a register. * @client: i2c client @@ -1036,13 +983,12 @@ static ssize_t tsl2x7x_als_time_store(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2X7X_chip *chip = iio_priv(indio_dev); struct tsl2x7x_parse_result result; + int ret; - result.integer = 0; - result.fract = 0; - - tsl2x7x_parse_buffer(buf, &result); + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; - result.fract /= 1000; result.fract /= 3; chip->tsl2x7x_settings.als_time = (TSL2X7X_MAX_TIMER_CNT - (u8)result.fract); @@ -1109,12 +1055,12 @@ static ssize_t tsl2x7x_als_persistence_store(struct device *dev, struct tsl2X7X_chip *chip = iio_priv(indio_dev); struct tsl2x7x_parse_result result; int y, z, filter_delay; + int ret; - result.integer = 0; - result.fract = 0; - tsl2x7x_parse_buffer(buf, &result); + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; - result.fract /= 1000; y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; z = y * TSL2X7X_MIN_ITIME; @@ -1155,12 +1101,12 @@ static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, struct tsl2X7X_chip *chip = iio_priv(indio_dev); struct tsl2x7x_parse_result result; int y, z, filter_delay; + int ret; - result.integer = 0; - result.fract = 0; - tsl2x7x_parse_buffer(buf, &result); + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; - result.fract /= 1000; y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; z = y * TSL2X7X_MIN_ITIME; From 06220b89f2284f910f925676d757fd3331138dc6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 05/40] staging:iio:adis16400: Don't pass 0 to ilog2 ilog2 is not defined for 0, so we need to handle the case where the requested frequency is larger than the base sampling rate. In this case we'll round down and set the sampling rate to the base sampling rate. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 9c8f5ab7e13b..cb6622578e9b 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -178,7 +178,11 @@ static int adis16334_set_freq(struct iio_dev *indio_dev, unsigned int freq) { unsigned int t; - t = ilog2(8192 / (freq * 10)); + freq *= 10; + if (freq < 8192) + t = ilog2(8192 / freq); + else + t = 0; if (t > 0x31) t = 0x31; From bdb20bdb8c1ea55c9a2f744cc5b2c7f66148a41b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 06/40] staging:iio:adis16400: Fix and cleanup 3db filter setting The 3db divisors table is partially wrong and incomplete. Also the code rounds up to the next higher frequency if the requested frequency would matches one of the available frequencies. These two issues are fixed by this patch. The patch also changes the driver to round down the filter frequency if it is larger than the largest supported frequency instead of rejecting it as an invalid value. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 41 ++++++++++++------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index cb6622578e9b..7114de94f412 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -242,33 +242,32 @@ static ssize_t adis16400_read_frequency(struct device *dev, static const unsigned adis16400_3db_divisors[] = { [0] = 2, /* Special case */ - [1] = 5, - [2] = 10, - [3] = 50, - [4] = 200, + [1] = 6, + [2] = 12, + [3] = 25, + [4] = 50, + [5] = 100, + [6] = 200, + [7] = 200, /* Not a valid setting */ }; static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) { int i, ret; u16 val16; - for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 0; i--) - if (sps/adis16400_3db_divisors[i] > val) + + for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { + if (sps / adis16400_3db_divisors[i] >= val) break; - if (i == -1) - ret = -EINVAL; - else { - ret = adis16400_spi_read_reg_16(indio_dev, - ADIS16400_SENS_AVG, + } + + ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SENS_AVG, &val16); - if (ret < 0) - goto error_ret; + if (ret < 0) + return ret; - ret = adis16400_spi_write_reg_16(indio_dev, - ADIS16400_SENS_AVG, - (val16 & ~0x03) | i); - } -error_ret: + ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SENS_AVG, + (val16 & ~0x07) | i); return ret; } @@ -653,9 +652,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return ret; } - val16 = st->variant->get_freq(indio_dev); - if (ret > 0) - *val = ret/adis16400_3db_divisors[val16 & 0x03]; + ret = st->variant->get_freq(indio_dev); + if (ret >= 0) + *val = ret / adis16400_3db_divisors[val16 & 0x07]; *val2 = 0; mutex_unlock(&indio_dev->mlock); if (ret < 0) From ca6907df6b5d86d848eac706f28c7a89126f3875 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 07/40] staging:iio:adis16400: Remove unused default_scan_mask The chip_info struct for contains a defaul_scan_mask field. But it is never actually used in the code, so remove it from the chip_info struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400.h | 1 - drivers/staging/iio/imu/adis16400_core.c | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 7a105e966464..3efafcbb886e 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -145,7 +145,6 @@ struct adis16400_chip_info { unsigned int accel_scale_micro; int temp_scale_nano; int temp_offset; - unsigned long default_scan_mask; int (*set_freq)(struct iio_dev *indio_dev, unsigned int freq); int (*get_freq)(struct iio_dev *indio_dev); }; diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 7114de94f412..24fca1033fb3 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -1116,12 +1116,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = 5884, .temp_scale_nano = 140000000, /* 0.14 C */ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .default_scan_mask = (1 << ADIS16400_SCAN_SUPPLY) | - (1 << ADIS16400_SCAN_GYRO_X) | (1 << ADIS16400_SCAN_ACC_X) | - (1 << ADIS16400_SCAN_ACC_Y) | (1 << ADIS16400_SCAN_ACC_Z) | - (1 << ADIS16400_SCAN_TEMP) | (1 << ADIS16400_SCAN_ADC_0) | - (1 << ADIS16300_SCAN_INCLI_X) | (1 << ADIS16300_SCAN_INCLI_Y) | - (1 << 14), .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, @@ -1133,10 +1127,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ .temp_scale_nano = 67850000, /* 0.06785 C */ .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ - .default_scan_mask = (1 << ADIS16400_SCAN_GYRO_X) | - (1 << ADIS16400_SCAN_GYRO_Y) | (1 << ADIS16400_SCAN_GYRO_Z) | - (1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_ACC_Y) | - (1 << ADIS16400_SCAN_ACC_Z), .set_freq = adis16334_set_freq, .get_freq = adis16334_get_freq, }, @@ -1147,7 +1137,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ .temp_scale_nano = 145300000, /* 0.1453 C */ .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ - .default_scan_mask = 0x7FF, .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, @@ -1160,7 +1149,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .default_scan_mask = 0x7FF, .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, @@ -1172,7 +1160,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .default_scan_mask = 0x7FF, .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, @@ -1184,7 +1171,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .default_scan_mask = 0x7FF, .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, @@ -1194,7 +1180,6 @@ static struct adis16400_chip_info adis16400_chips[] = { .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .default_scan_mask = 0xFFF, .temp_scale_nano = 140000000, /* 0.14 C */ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ .set_freq = adis16400_set_freq, From cd888a17f95fb170f6463990a6a24b4cd5fedea6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 08/40] staging:iio:adis16400: Use adis library Use the new adis library for the adis16400 driver. This allows us to completely scrap the adis16400 trigger code and more than half of the core driver code. For now we can not make use of the generic adis buffer implementation since the adis16400 driver has special requirements due to its burst mode support. But we will eventually get to this. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/Kconfig | 4 +- drivers/staging/iio/imu/Makefile | 2 +- drivers/staging/iio/imu/adis16400.h | 109 ++-- drivers/staging/iio/imu/adis16400_core.c | 535 ++++++-------------- drivers/staging/iio/imu/adis16400_ring.c | 59 +-- drivers/staging/iio/imu/adis16400_trigger.c | 74 --- 6 files changed, 225 insertions(+), 558 deletions(-) delete mode 100644 drivers/staging/iio/imu/adis16400_trigger.c diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig index 2c2f47de2630..096afc8cd87e 100644 --- a/drivers/staging/iio/imu/Kconfig +++ b/drivers/staging/iio/imu/Kconfig @@ -6,8 +6,8 @@ menu "Inertial measurement units" config ADIS16400 tristate "Analog Devices ADIS16400 and similar IMU SPI driver" depends on SPI - select IIO_SW_RING if IIO_BUFFER - select IIO_TRIGGER if IIO_BUFFER + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER help Say yes here to build support for Analog Devices adis16300, adis16344, adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile index 3400a13d1522..c9988f6077ff 100644 --- a/drivers/staging/iio/imu/Makefile +++ b/drivers/staging/iio/imu/Makefile @@ -3,5 +3,5 @@ # adis16400-y := adis16400_core.o -adis16400-$(CONFIG_IIO_BUFFER) += adis16400_ring.o adis16400_trigger.o +adis16400-$(CONFIG_IIO_BUFFER) += adis16400_ring.o obj-$(CONFIG_ADIS16400) += adis16400.o diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 3efafcbb886e..ce63ced77c7f 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -17,12 +17,11 @@ #ifndef SPI_ADIS16400_H_ #define SPI_ADIS16400_H_ +#include + #define ADIS16400_STARTUP_DELAY 290 /* ms */ #define ADIS16400_MTEST_DELAY 90 /* ms */ -#define ADIS16400_READ_REG(a) a -#define ADIS16400_WRITE_REG(a) ((a) | 0x80) - #define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ #define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ #define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ @@ -96,21 +95,21 @@ #define ADIS16400_SMPL_PRD_DIV_MASK 0x7F /* DIAG_STAT */ -#define ADIS16400_DIAG_STAT_ZACCL_FAIL (1<<15) -#define ADIS16400_DIAG_STAT_YACCL_FAIL (1<<14) -#define ADIS16400_DIAG_STAT_XACCL_FAIL (1<<13) -#define ADIS16400_DIAG_STAT_XGYRO_FAIL (1<<12) -#define ADIS16400_DIAG_STAT_YGYRO_FAIL (1<<11) -#define ADIS16400_DIAG_STAT_ZGYRO_FAIL (1<<10) -#define ADIS16400_DIAG_STAT_ALARM2 (1<<9) -#define ADIS16400_DIAG_STAT_ALARM1 (1<<8) -#define ADIS16400_DIAG_STAT_FLASH_CHK (1<<6) -#define ADIS16400_DIAG_STAT_SELF_TEST (1<<5) -#define ADIS16400_DIAG_STAT_OVERFLOW (1<<4) -#define ADIS16400_DIAG_STAT_SPI_FAIL (1<<3) -#define ADIS16400_DIAG_STAT_FLASH_UPT (1<<2) -#define ADIS16400_DIAG_STAT_POWER_HIGH (1<<1) -#define ADIS16400_DIAG_STAT_POWER_LOW (1<<0) +#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 +#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 +#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 +#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 +#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 +#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 +#define ADIS16400_DIAG_STAT_ALARM2 9 +#define ADIS16400_DIAG_STAT_ALARM1 8 +#define ADIS16400_DIAG_STAT_FLASH_CHK 6 +#define ADIS16400_DIAG_STAT_SELF_TEST 5 +#define ADIS16400_DIAG_STAT_OVERFLOW 4 +#define ADIS16400_DIAG_STAT_SPI_FAIL 3 +#define ADIS16400_DIAG_STAT_FLASH_UPT 2 +#define ADIS16400_DIAG_STAT_POWER_HIGH 1 +#define ADIS16400_DIAG_STAT_POWER_LOW 0 /* GLOB_CMD */ #define ADIS16400_GLOB_CMD_SW_RESET (1<<7) @@ -126,9 +125,6 @@ #define ADIS16334_RATE_DIV_SHIFT 8 #define ADIS16334_RATE_INT_CLK BIT(0) -#define ADIS16400_MAX_TX 24 -#define ADIS16400_MAX_RX 24 - #define ADIS16400_SPI_SLOW (u32)(300 * 1000) #define ADIS16400_SPI_BURST (u32)(1000 * 1000) #define ADIS16400_SPI_FAST (u32)(2000 * 1000) @@ -137,6 +133,8 @@ #define ADIS16400_NO_BURST BIT(1) #define ADIS16400_HAS_SLOW_MODE BIT(2) +struct adis16400_state; + struct adis16400_chip_info { const struct iio_chan_spec *channels; const int num_channels; @@ -145,58 +143,47 @@ struct adis16400_chip_info { unsigned int accel_scale_micro; int temp_scale_nano; int temp_offset; - int (*set_freq)(struct iio_dev *indio_dev, unsigned int freq); - int (*get_freq)(struct iio_dev *indio_dev); + int (*set_freq)(struct adis16400_state *st, unsigned int freq); + int (*get_freq)(struct adis16400_state *st); }; /** * struct adis16400_state - device instance specific data - * @us: actual spi_device - * @trig: data ready trigger registered with iio - * @tx: transmit buffer - * @rx: receive buffer - * @buf_lock: mutex to protect tx and rx - * @filt_int: integer part of requested filter frequency + * @variant: chip variant info + * @filt_int: integer part of requested filter frequency + * @adis: adis device **/ struct adis16400_state { - struct spi_device *us; - struct iio_trigger *trig; - struct mutex buf_lock; struct adis16400_chip_info *variant; int filt_int; - u8 tx[ADIS16400_MAX_TX] ____cacheline_aligned; - u8 rx[ADIS16400_MAX_RX] ____cacheline_aligned; + struct adis adis; }; -int adis16400_set_irq(struct iio_dev *indio_dev, bool enable); - /* At the moment triggers are only used for ring buffer * filling. This may change! */ -#define ADIS16400_SCAN_SUPPLY 0 -#define ADIS16400_SCAN_GYRO_X 1 -#define ADIS16400_SCAN_GYRO_Y 2 -#define ADIS16400_SCAN_GYRO_Z 3 -#define ADIS16400_SCAN_ACC_X 4 -#define ADIS16400_SCAN_ACC_Y 5 -#define ADIS16400_SCAN_ACC_Z 6 -#define ADIS16400_SCAN_MAGN_X 7 -#define ADIS16350_SCAN_TEMP_X 7 -#define ADIS16400_SCAN_MAGN_Y 8 -#define ADIS16350_SCAN_TEMP_Y 8 -#define ADIS16400_SCAN_MAGN_Z 9 -#define ADIS16350_SCAN_TEMP_Z 9 -#define ADIS16400_SCAN_TEMP 10 -#define ADIS16350_SCAN_ADC_0 10 -#define ADIS16400_SCAN_ADC_0 11 -#define ADIS16300_SCAN_INCLI_X 12 -#define ADIS16300_SCAN_INCLI_Y 13 +enum { + ADIS16400_SCAN_SUPPLY, + ADIS16400_SCAN_GYRO_X, + ADIS16400_SCAN_GYRO_Y, + ADIS16400_SCAN_GYRO_Z, + ADIS16400_SCAN_ACC_X, + ADIS16400_SCAN_ACC_Y, + ADIS16400_SCAN_ACC_Z, + ADIS16400_SCAN_MAGN_X, + ADIS16400_SCAN_MAGN_Y, + ADIS16400_SCAN_MAGN_Z, + ADIS16350_SCAN_TEMP_X, + ADIS16350_SCAN_TEMP_Y, + ADIS16350_SCAN_TEMP_Z, + ADIS16300_SCAN_INCLI_X, + ADIS16300_SCAN_INCLI_Y, + ADIS16400_SCAN_ADC, +}; #ifdef CONFIG_IIO_BUFFER -void adis16400_remove_trigger(struct iio_dev *indio_dev); -int adis16400_probe_trigger(struct iio_dev *indio_dev); ssize_t adis16400_read_data_from_ring(struct device *dev, struct device_attribute *attr, @@ -208,15 +195,6 @@ void adis16400_unconfigure_ring(struct iio_dev *indio_dev); #else /* CONFIG_IIO_BUFFER */ -static inline void adis16400_remove_trigger(struct iio_dev *indio_dev) -{ -} - -static inline int adis16400_probe_trigger(struct iio_dev *indio_dev) -{ - return 0; -} - static inline ssize_t adis16400_read_data_from_ring(struct device *dev, struct device_attribute *attr, @@ -235,4 +213,5 @@ static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev) } #endif /* CONFIG_IIO_BUFFER */ + #endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 24fca1033fb3..a948472856ed 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -29,6 +29,7 @@ #include #include #include + #include "adis16400.h" enum adis16400_chip_variant { @@ -41,131 +42,12 @@ enum adis16400_chip_variant { ADIS16400, }; -/** - * adis16400_spi_write_reg_8() - write single byte to a register - * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @reg_address: the address of the register to be written - * @val: the value to write - */ -static int adis16400_spi_write_reg_8(struct iio_dev *indio_dev, - u8 reg_address, - u8 val) -{ - int ret; - struct adis16400_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_WRITE_REG(reg_address); - st->tx[1] = val; - - ret = spi_write(st->us, st->tx, 2); - mutex_unlock(&st->buf_lock); - - return ret; -} - -/** - * adis16400_spi_write_reg_16() - write 2 bytes to a pair of registers - * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @reg_address: the address of the lower of the two registers. Second register - * is assumed to have address one greater. - * @val: value to be written - * - * At the moment the spi framework doesn't allow global setting of cs_change. - * This means that use cannot be made of spi_write. - */ -static int adis16400_spi_write_reg_16(struct iio_dev *indio_dev, - u8 lower_reg_address, - u16 value) -{ - int ret; - struct spi_message msg; - struct adis16400_state *st = iio_priv(indio_dev); - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .tx_buf = st->tx + 2, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_WRITE_REG(lower_reg_address); - st->tx[1] = value & 0xFF; - st->tx[2] = ADIS16400_WRITE_REG(lower_reg_address + 1); - st->tx[3] = (value >> 8) & 0xFF; - - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); - mutex_unlock(&st->buf_lock); - - return ret; -} - -/** - * adis16400_spi_read_reg_16() - read 2 bytes from a 16-bit register - * @indio_dev: iio device - * @reg_address: the address of the lower of the two registers. Second register - * is assumed to have address one greater. - * @val: somewhere to pass back the value read - * - * At the moment the spi framework doesn't allow global setting of cs_change. - * This means that use cannot be made of spi_read. - **/ -static int adis16400_spi_read_reg_16(struct iio_dev *indio_dev, - u8 lower_reg_address, - u16 *val) -{ - struct spi_message msg; - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_READ_REG(lower_reg_address); - st->tx[1] = 0; - - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); - if (ret) { - dev_err(&st->us->dev, - "problem when reading 16 bit register 0x%02X", - lower_reg_address); - goto error_ret; - } - *val = (st->rx[0] << 8) | st->rx[1]; - -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int adis16334_get_freq(struct iio_dev *indio_dev) +static int adis16334_get_freq(struct adis16400_state *st) { int ret; u16 t; - ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t); + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret < 0) return ret; @@ -174,7 +56,7 @@ static int adis16334_get_freq(struct iio_dev *indio_dev) return (8192 >> t) / 10; } -static int adis16334_set_freq(struct iio_dev *indio_dev, unsigned int freq) +static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) { unsigned int t; @@ -190,15 +72,15 @@ static int adis16334_set_freq(struct iio_dev *indio_dev, unsigned int freq) t <<= ADIS16334_RATE_DIV_SHIFT; t |= ADIS16334_RATE_INT_CLK; - return adis16400_spi_write_reg_16(indio_dev, ADIS16400_SMPL_PRD, t); + return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); } -static int adis16400_get_freq(struct iio_dev *indio_dev) +static int adis16400_get_freq(struct adis16400_state *st) { int sps, ret; u16 t; - ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t); + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret < 0) return ret; sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; @@ -207,9 +89,8 @@ static int adis16400_get_freq(struct iio_dev *indio_dev) return sps; } -static int adis16400_set_freq(struct iio_dev *indio_dev, unsigned int freq) +static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) { - struct adis16400_state *st = iio_priv(indio_dev); unsigned int t; t = 1638 / freq; @@ -217,12 +98,11 @@ static int adis16400_set_freq(struct iio_dev *indio_dev, unsigned int freq) t--; t &= ADIS16400_SMPL_PRD_DIV_MASK; if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) - st->us->max_speed_hz = ADIS16400_SPI_SLOW; + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; else - st->us->max_speed_hz = ADIS16400_SPI_FAST; + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - return adis16400_spi_write_reg_8(indio_dev, - ADIS16400_SMPL_PRD, t); + return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); } static ssize_t adis16400_read_frequency(struct device *dev, @@ -233,7 +113,7 @@ static ssize_t adis16400_read_frequency(struct device *dev, struct adis16400_state *st = iio_priv(indio_dev); int ret, len = 0; - ret = st->variant->get_freq(indio_dev); + ret = st->variant->get_freq(st); if (ret < 0) return ret; len = sprintf(buf, "%d SPS\n", ret); @@ -253,6 +133,7 @@ static const unsigned adis16400_3db_divisors[] = { static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) { + struct adis16400_state *st = iio_priv(indio_dev); int i, ret; u16 val16; @@ -261,12 +142,11 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) break; } - ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SENS_AVG, - &val16); + ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret < 0) return ret; - ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SENS_AVG, + ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, (val16 & ~0x07) | i); return ret; } @@ -289,7 +169,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, mutex_lock(&indio_dev->mlock); - st->variant->set_freq(indio_dev, val); + st->variant->set_freq(st, val); /* Also update the filter */ mutex_unlock(&indio_dev->mlock); @@ -297,48 +177,14 @@ static ssize_t adis16400_write_frequency(struct device *dev, return ret ? ret : len; } -static int adis16400_reset(struct iio_dev *indio_dev) -{ - int ret; - ret = adis16400_spi_write_reg_8(indio_dev, - ADIS16400_GLOB_CMD, - ADIS16400_GLOB_CMD_SW_RESET); - if (ret) - dev_err(&indio_dev->dev, "problem resetting device"); - - return ret; -} - -int adis16400_set_irq(struct iio_dev *indio_dev, bool enable) -{ - int ret; - u16 msc; - - ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_MSC_CTRL, &msc); - if (ret) - goto error_ret; - - msc |= ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH; - if (enable) - msc |= ADIS16400_MSC_CTRL_DATA_RDY_EN; - else - msc &= ~ADIS16400_MSC_CTRL_DATA_RDY_EN; - - ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_MSC_CTRL, msc); - if (ret) - goto error_ret; - -error_ret: - return ret; -} - /* Power down the device */ static int adis16400_stop_device(struct iio_dev *indio_dev) { + struct adis16400_state *st = iio_priv(indio_dev); int ret; u16 val = ADIS16400_SLP_CNT_POWER_OFF; - ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SLP_CNT, val); + ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, val); if (ret) dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); @@ -346,73 +192,6 @@ static int adis16400_stop_device(struct iio_dev *indio_dev) return ret; } -static int adis16400_check_status(struct iio_dev *indio_dev) -{ - u16 status; - int ret; - struct device *dev = &indio_dev->dev; - - ret = adis16400_spi_read_reg_16(indio_dev, - ADIS16400_DIAG_STAT, &status); - - if (ret < 0) { - dev_err(dev, "Reading status failed\n"); - goto error_ret; - } - ret = status; - if (status & ADIS16400_DIAG_STAT_ZACCL_FAIL) - dev_err(dev, "Z-axis accelerometer self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_YACCL_FAIL) - dev_err(dev, "Y-axis accelerometer self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_XACCL_FAIL) - dev_err(dev, "X-axis accelerometer self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_XGYRO_FAIL) - dev_err(dev, "X-axis gyroscope self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_YGYRO_FAIL) - dev_err(dev, "Y-axis gyroscope self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_ZGYRO_FAIL) - dev_err(dev, "Z-axis gyroscope self-test failure\n"); - if (status & ADIS16400_DIAG_STAT_ALARM2) - dev_err(dev, "Alarm 2 active\n"); - if (status & ADIS16400_DIAG_STAT_ALARM1) - dev_err(dev, "Alarm 1 active\n"); - if (status & ADIS16400_DIAG_STAT_FLASH_CHK) - dev_err(dev, "Flash checksum error\n"); - if (status & ADIS16400_DIAG_STAT_SELF_TEST) - dev_err(dev, "Self test error\n"); - if (status & ADIS16400_DIAG_STAT_OVERFLOW) - dev_err(dev, "Sensor overrange\n"); - if (status & ADIS16400_DIAG_STAT_SPI_FAIL) - dev_err(dev, "SPI failure\n"); - if (status & ADIS16400_DIAG_STAT_FLASH_UPT) - dev_err(dev, "Flash update failed\n"); - if (status & ADIS16400_DIAG_STAT_POWER_HIGH) - dev_err(dev, "Power supply above 5.25V\n"); - if (status & ADIS16400_DIAG_STAT_POWER_LOW) - dev_err(dev, "Power supply below 4.75V\n"); - -error_ret: - return ret; -} - -static int adis16400_self_test(struct iio_dev *indio_dev) -{ - int ret; - ret = adis16400_spi_write_reg_16(indio_dev, - ADIS16400_MSC_CTRL, - ADIS16400_MSC_CTRL_MEM_TEST); - if (ret) { - dev_err(&indio_dev->dev, "problem starting self test"); - goto err_ret; - } - - msleep(ADIS16400_MTEST_DELAY); - adis16400_check_status(indio_dev); - -err_ret: - return ret; -} - static int adis16400_initial_setup(struct iio_dev *indio_dev) { int ret; @@ -422,37 +201,18 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev) /* use low spi speed for init if the device has a slow mode */ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) - st->us->max_speed_hz = ADIS16400_SPI_SLOW; + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; else - st->us->max_speed_hz = ADIS16400_SPI_FAST; - st->us->mode = SPI_MODE_3; - spi_setup(st->us); - - ret = adis16400_set_irq(indio_dev, false); - if (ret) { - dev_err(&indio_dev->dev, "disable irq failed"); - goto err_ret; - } + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; + st->adis.spi->mode = SPI_MODE_3; + spi_setup(st->adis.spi); - ret = adis16400_self_test(indio_dev); - if (ret) { - dev_err(&indio_dev->dev, "self test failure"); - goto err_ret; - } + ret = adis_initial_startup(&st->adis); + if (ret) + return ret; - ret = adis16400_check_status(indio_dev); - if (ret) { - adis16400_reset(indio_dev); - dev_err(&indio_dev->dev, "device not playing ball -> reset"); - msleep(ADIS16400_STARTUP_DELAY); - ret = adis16400_check_status(indio_dev); - if (ret) { - dev_err(&indio_dev->dev, "giving up"); - goto err_ret; - } - } if (st->variant->flags & ADIS16400_HAS_PROD_ID) { - ret = adis16400_spi_read_reg_16(indio_dev, + ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id); if (ret) goto err_ret; @@ -465,18 +225,17 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev) dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", indio_dev->name, prod_id, - st->us->chip_select, st->us->irq); + st->adis.spi->chip_select, st->adis.spi->irq); } /* use high spi speed if possible */ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { - ret = adis16400_spi_read_reg_16(indio_dev, - ADIS16400_SMPL_PRD, &smp_prd); + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); if (ret) goto err_ret; if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { - st->us->max_speed_hz = ADIS16400_SPI_FAST; - spi_setup(st->us); + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; + spi_setup(st->adis.spi); } } @@ -490,47 +249,15 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); -enum adis16400_chan { - in_supply, - gyro_x, - gyro_y, - gyro_z, - accel_x, - accel_y, - accel_z, - magn_x, - magn_y, - magn_z, - temp, - temp0, temp1, temp2, - in1, - in2, - incli_x, - incli_y, -}; - -static u8 adis16400_addresses[18][2] = { - [in_supply] = { ADIS16400_SUPPLY_OUT }, - [gyro_x] = { ADIS16400_XGYRO_OUT, ADIS16400_XGYRO_OFF }, - [gyro_y] = { ADIS16400_YGYRO_OUT, ADIS16400_YGYRO_OFF }, - [gyro_z] = { ADIS16400_ZGYRO_OUT, ADIS16400_ZGYRO_OFF }, - [accel_x] = { ADIS16400_XACCL_OUT, ADIS16400_XACCL_OFF }, - [accel_y] = { ADIS16400_YACCL_OUT, ADIS16400_YACCL_OFF }, - [accel_z] = { ADIS16400_ZACCL_OUT, ADIS16400_ZACCL_OFF }, - [magn_x] = { ADIS16400_XMAGN_OUT }, - [magn_y] = { ADIS16400_YMAGN_OUT }, - [magn_z] = { ADIS16400_ZMAGN_OUT }, - [temp] = { ADIS16400_TEMP_OUT }, - [temp0] = { ADIS16350_XTEMP_OUT }, - [temp1] = { ADIS16350_YTEMP_OUT }, - [temp2] = { ADIS16350_ZTEMP_OUT }, - [in1] = { ADIS16300_AUX_ADC }, - [in2] = { ADIS16400_AUX_ADC }, - [incli_x] = { ADIS16300_PITCH_OUT }, - [incli_y] = { ADIS16300_ROLL_OUT } +static const u8 adis16400_addresses[] = { + [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, + [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, + [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, + [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, + [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, + [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, }; - static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -543,9 +270,8 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&indio_dev->mlock); - ret = adis16400_spi_write_reg_16(indio_dev, - adis16400_addresses[chan->address][1], - val); + ret = adis_write_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], val); mutex_unlock(&indio_dev->mlock); return ret; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: @@ -554,7 +280,7 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); st->filt_int = val; /* Work out update to current value */ - sps = st->variant->get_freq(indio_dev); + sps = st->variant->get_freq(st); if (sps < 0) { mutex_unlock(&indio_dev->mlock); return sps; @@ -575,27 +301,12 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, long mask) { struct adis16400_state *st = iio_priv(indio_dev); - int ret, shift; + int ret; s16 val16; switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - ret = adis16400_spi_read_reg_16(indio_dev, - adis16400_addresses[chan->address][0], - &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << chan->scan_type.realbits) - 1; - if (chan->scan_type.sign == 's') { - shift = 16 - chan->scan_type.realbits; - val16 = (s16)(val16 << shift) >> shift; - } - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; + return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: @@ -629,9 +340,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&indio_dev->mlock); - ret = adis16400_spi_read_reg_16(indio_dev, - adis16400_addresses[chan->address][1], - &val16); + ret = adis_read_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], &val16); mutex_unlock(&indio_dev->mlock); if (ret) return ret; @@ -645,14 +355,14 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: mutex_lock(&indio_dev->mlock); /* Need both the number of taps and the sampling frequency */ - ret = adis16400_spi_read_reg_16(indio_dev, + ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret < 0) { mutex_unlock(&indio_dev->mlock); return ret; } - ret = st->variant->get_freq(indio_dev); + ret = st->variant->get_freq(st); if (ret >= 0) *val = ret / adis16400_3db_divisors[val16 & 0x07]; *val2 = 0; @@ -673,7 +383,7 @@ static const struct iio_chan_spec adis16400_channels[] = { .extend_name = "supply", .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in_supply, + .address = ADIS16400_SUPPLY_OUT, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 14, 16, 0), }, { @@ -684,7 +394,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_x, + .address = ADIS16400_XGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -695,7 +405,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_y, + .address = ADIS16400_YGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -706,7 +416,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_z, + .address = ADIS16400_ZGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -717,7 +427,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_x, + .address = ADIS16400_XACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -728,7 +438,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_y, + .address = ADIS16400_YACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -739,7 +449,7 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_z, + .address = ADIS16400_ZACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -749,7 +459,7 @@ static const struct iio_chan_spec adis16400_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = magn_x, + .address = ADIS16400_XMAGN_OUT, .scan_index = ADIS16400_SCAN_MAGN_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -759,7 +469,7 @@ static const struct iio_chan_spec adis16400_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = magn_y, + .address = ADIS16400_YMAGN_OUT, .scan_index = ADIS16400_SCAN_MAGN_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -769,7 +479,7 @@ static const struct iio_chan_spec adis16400_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = magn_z, + .address = ADIS16400_ZMAGN_OUT, .scan_index = ADIS16400_SCAN_MAGN_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -779,8 +489,8 @@ static const struct iio_chan_spec adis16400_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = temp, - .scan_index = ADIS16400_SCAN_TEMP, + .address = ADIS16400_TEMP_OUT, + .scan_index = ADIS16350_SCAN_TEMP_X, .scan_type = IIO_ST('s', 12, 16, 0), }, { .type = IIO_VOLTAGE, @@ -788,8 +498,8 @@ static const struct iio_chan_spec adis16400_channels[] = { .channel = 1, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in2, - .scan_index = ADIS16400_SCAN_ADC_0, + .address = ADIS16400_AUX_ADC, + .scan_index = ADIS16400_SCAN_ADC, .scan_type = IIO_ST('s', 12, 16, 0), }, IIO_CHAN_SOFT_TIMESTAMP(12) @@ -803,7 +513,7 @@ static const struct iio_chan_spec adis16350_channels[] = { .extend_name = "supply", .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in_supply, + .address = ADIS16400_SUPPLY_OUT, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0), }, { @@ -814,7 +524,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_x, + .address = ADIS16400_XGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -825,7 +535,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_y, + .address = ADIS16400_YGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -836,7 +546,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_z, + .address = ADIS16400_ZGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -847,7 +557,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_x, + .address = ADIS16400_XACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -858,7 +568,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_y, + .address = ADIS16400_YACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -869,7 +579,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_z, + .address = ADIS16400_ZACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -881,7 +591,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = temp0, + .address = ADIS16350_XTEMP_OUT, .scan_index = ADIS16350_SCAN_TEMP_X, .scan_type = IIO_ST('s', 12, 16, 0), }, { @@ -893,7 +603,7 @@ static const struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = temp1, + .address = ADIS16350_YTEMP_OUT, .scan_index = ADIS16350_SCAN_TEMP_Y, .scan_type = IIO_ST('s', 12, 16, 0), }, { @@ -904,7 +614,7 @@ static const struct iio_chan_spec adis16350_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = temp2, + .address = ADIS16350_ZTEMP_OUT, .scan_index = ADIS16350_SCAN_TEMP_Z, .scan_type = IIO_ST('s', 12, 16, 0), }, { @@ -913,8 +623,8 @@ static const struct iio_chan_spec adis16350_channels[] = { .channel = 1, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in1, - .scan_index = ADIS16350_SCAN_ADC_0, + .address = ADIS16300_AUX_ADC, + .scan_index = ADIS16400_SCAN_ADC, .scan_type = IIO_ST('s', 12, 16, 0), }, IIO_CHAN_SOFT_TIMESTAMP(11) @@ -928,7 +638,7 @@ static const struct iio_chan_spec adis16300_channels[] = { .extend_name = "supply", .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in_supply, + .address = ADIS16400_SUPPLY_OUT, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0), }, { @@ -939,7 +649,7 @@ static const struct iio_chan_spec adis16300_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_x, + .address = ADIS16400_XGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -950,7 +660,7 @@ static const struct iio_chan_spec adis16300_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_x, + .address = ADIS16400_XACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -961,7 +671,7 @@ static const struct iio_chan_spec adis16300_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_y, + .address = ADIS16400_YACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -972,7 +682,7 @@ static const struct iio_chan_spec adis16300_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_z, + .address = ADIS16400_ZACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -982,8 +692,8 @@ static const struct iio_chan_spec adis16300_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = temp0, - .scan_index = ADIS16400_SCAN_TEMP, + .address = ADIS16350_XTEMP_OUT, + .scan_index = ADIS16350_SCAN_TEMP_X, .scan_type = IIO_ST('s', 12, 16, 0), }, { .type = IIO_VOLTAGE, @@ -991,8 +701,8 @@ static const struct iio_chan_spec adis16300_channels[] = { .channel = 1, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = in1, - .scan_index = ADIS16350_SCAN_ADC_0, + .address = ADIS16300_AUX_ADC, + .scan_index = ADIS16400_SCAN_ADC, .scan_type = IIO_ST('s', 12, 16, 0), }, { .type = IIO_INCLI, @@ -1000,7 +710,7 @@ static const struct iio_chan_spec adis16300_channels[] = { .channel2 = IIO_MOD_X, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = incli_x, + .address = ADIS16300_PITCH_OUT, .scan_index = ADIS16300_SCAN_INCLI_X, .scan_type = IIO_ST('s', 13, 16, 0), }, { @@ -1009,7 +719,7 @@ static const struct iio_chan_spec adis16300_channels[] = { .channel2 = IIO_MOD_Y, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = incli_y, + .address = ADIS16300_ROLL_OUT, .scan_index = ADIS16300_SCAN_INCLI_Y, .scan_type = IIO_ST('s', 13, 16, 0), }, @@ -1025,7 +735,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_x, + .address = ADIS16400_XGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1036,7 +746,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_y, + .address = ADIS16400_YGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1047,7 +757,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = gyro_z, + .address = ADIS16400_ZGYRO_OUT, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1058,7 +768,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_x, + .address = ADIS16400_XACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_X, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1069,7 +779,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_y, + .address = ADIS16400_YACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Y, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1080,7 +790,7 @@ static const struct iio_chan_spec adis16334_channels[] = { IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = accel_z, + .address = ADIS16400_ZACCL_OUT, .scan_index = ADIS16400_SCAN_ACC_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { @@ -1090,8 +800,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = temp0, - .scan_index = ADIS16400_SCAN_TEMP, + .address = ADIS16350_XTEMP_OUT, + .scan_index = ADIS16350_SCAN_TEMP_X, .scan_type = IIO_ST('s', 14, 16, 0), }, IIO_CHAN_SOFT_TIMESTAMP(12) @@ -1194,6 +904,53 @@ static const struct iio_info adis16400_info = { .attrs = &adis16400_attribute_group, }; +static const char * const adis16400_status_error_msgs[] = { + [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", + [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", + [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", + [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", + [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", + [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", + [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", + [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", + [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", +}; + +static const struct adis_data adis16400_data = { + .msc_ctrl_reg = ADIS16400_MSC_CTRL, + .glob_cmd_reg = ADIS16400_GLOB_CMD, + .diag_stat_reg = ADIS16400_DIAG_STAT, + + .read_delay = 50, + .write_delay = 50, + + .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, + .startup_delay = ADIS16400_STARTUP_DELAY, + + .status_error_msgs = adis16400_status_error_msgs, + .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_ALARM2) | + BIT(ADIS16400_DIAG_STAT_ALARM1) | + BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | + BIT(ADIS16400_DIAG_STAT_SELF_TEST) | + BIT(ADIS16400_DIAG_STAT_OVERFLOW) | + BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | + BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | + BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | + BIT(ADIS16400_DIAG_STAT_POWER_LOW), +}; + static int adis16400_probe(struct spi_device *spi) { int ret; @@ -1207,9 +964,6 @@ static int adis16400_probe(struct spi_device *spi) /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); - st->us = spi; - mutex_init(&st->buf_lock); - /* setup the industrialio driver allocated elements */ st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; indio_dev->dev.parent = &spi->dev; @@ -1219,6 +973,10 @@ static int adis16400_probe(struct spi_device *spi) indio_dev->info = &adis16400_info; indio_dev->modes = INDIO_DIRECT_MODE; + ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); + if (ret) + goto error_free_dev; + ret = adis16400_configure_ring(indio_dev); if (ret) goto error_free_dev; @@ -1232,7 +990,7 @@ static int adis16400_probe(struct spi_device *spi) } if (spi->irq) { - ret = adis16400_probe_trigger(indio_dev); + ret = adis_probe_trigger(&st->adis, indio_dev); if (ret) goto error_uninitialize_ring; } @@ -1249,7 +1007,7 @@ static int adis16400_probe(struct spi_device *spi) error_remove_trigger: if (spi->irq) - adis16400_remove_trigger(indio_dev); + adis_remove_trigger(&st->adis); error_uninitialize_ring: iio_buffer_unregister(indio_dev); error_unreg_ring_funcs: @@ -1264,13 +1022,16 @@ static int adis16400_probe(struct spi_device *spi) static int adis16400_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis16400_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); adis16400_stop_device(indio_dev); - adis16400_remove_trigger(indio_dev); + if (spi->irq) + adis_remove_trigger(&st->adis); iio_buffer_unregister(indio_dev); adis16400_unconfigure_ring(indio_dev); + iio_device_free(indio_dev); return 0; diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index d46c1e38cf7b..6c5b0be71900 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -9,6 +9,7 @@ #include #include "../ring_sw.h" #include + #include "adis16400.h" /** @@ -20,12 +21,12 @@ static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; struct adis16400_state *st = iio_priv(indio_dev); - u32 old_speed_hz = st->us->max_speed_hz; + u32 old_speed_hz = st->adis.spi->max_speed_hz; int ret; struct spi_transfer xfers[] = { { - .tx_buf = st->tx, + .tx_buf = st->adis.tx, .bits_per_word = 8, .len = 2, }, { @@ -35,39 +36,39 @@ static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx) }, }; - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_READ_REG(ADIS16400_GLOB_CMD); - st->tx[1] = 0; + mutex_lock(&st->adis.txrx_lock); + st->adis.tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); + st->adis.tx[1] = 0; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); spi_message_add_tail(&xfers[1], &msg); - st->us->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz); - spi_setup(st->us); + st->adis.spi->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz); + spi_setup(st->adis.spi); - ret = spi_sync(st->us, &msg); + ret = spi_sync(st->adis.spi, &msg); if (ret) - dev_err(&st->us->dev, "problem when burst reading"); + dev_err(&st->adis.spi->dev, "problem when burst reading"); - st->us->max_speed_hz = old_speed_hz; - spi_setup(st->us); - mutex_unlock(&st->buf_lock); + st->adis.spi->max_speed_hz = old_speed_hz; + spi_setup(st->adis.spi); + mutex_unlock(&st->adis.txrx_lock); return ret; } static const u16 read_all_tx_array[] = { - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_SUPPLY_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_XGYRO_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_YGYRO_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_ZGYRO_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_XACCL_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_YACCL_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_ZACCL_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16350_XTEMP_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16350_YTEMP_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16350_ZTEMP_OUT)), - cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_SUPPLY_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_XGYRO_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_YGYRO_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_ZGYRO_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_XACCL_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_YACCL_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_ZACCL_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16350_XTEMP_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16350_YTEMP_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16350_ZTEMP_OUT)), + cpu_to_be16(ADIS_READ_REG(ADIS16400_AUX_ADC)), }; static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx) @@ -100,7 +101,7 @@ static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx) for (j = 0; j < scan_count + 1; j++) spi_message_add_tail(&xfers[j], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync(st->adis.spi, &msg); kfree(xfers); return ret; @@ -123,26 +124,26 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) indio_dev->masklength); data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { - dev_err(&st->us->dev, "memory alloc failed in ring bh"); + dev_err(&st->adis.spi->dev, "memory alloc failed in ring bh"); goto done; } if (scan_count) { if (st->variant->flags & ADIS16400_NO_BURST) { - ret = adis16350_spi_read_all(indio_dev, st->rx); + ret = adis16350_spi_read_all(indio_dev, st->adis.rx); if (ret < 0) goto done; for (; i < scan_count; i++) - data[i] = *(s16 *)(st->rx + i*2); + data[i] = *(s16 *)(st->adis.rx + i*2); } else { - ret = adis16400_spi_read_burst(indio_dev, st->rx); + ret = adis16400_spi_read_burst(indio_dev, st->adis.rx); if (ret < 0) goto done; for (; i < scan_count; i++) { j = __ffs(mask); mask &= ~(1 << j); data[i] = be16_to_cpup( - (__be16 *)&(st->rx[j*2])); + (__be16 *)&(st->adis.rx[j*2])); } } } diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c deleted file mode 100644 index 42a678e92fc6..000000000000 --- a/drivers/staging/iio/imu/adis16400_trigger.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include "adis16400.h" - -/** - * adis16400_data_rdy_trigger_set_state() set datardy interrupt state - **/ -static int adis16400_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - struct iio_dev *indio_dev = trig->private_data; - - dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); - return adis16400_set_irq(indio_dev, state); -} - -static const struct iio_trigger_ops adis16400_trigger_ops = { - .owner = THIS_MODULE, - .set_trigger_state = &adis16400_data_rdy_trigger_set_state, -}; - -int adis16400_probe_trigger(struct iio_dev *indio_dev) -{ - int ret; - struct adis16400_state *st = iio_priv(indio_dev); - - st->trig = iio_trigger_alloc("%s-dev%d", - indio_dev->name, - indio_dev->id); - if (st->trig == NULL) { - ret = -ENOMEM; - goto error_ret; - } - - ret = request_irq(st->us->irq, - &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - "adis16400", - st->trig); - if (ret) - goto error_free_trig; - st->trig->dev.parent = &st->us->dev; - st->trig->private_data = indio_dev; - st->trig->ops = &adis16400_trigger_ops; - ret = iio_trigger_register(st->trig); - - /* select default trigger */ - indio_dev->trig = st->trig; - if (ret) - goto error_free_irq; - - return 0; - -error_free_irq: - free_irq(st->us->irq, st->trig); -error_free_trig: - iio_trigger_free(st->trig); -error_ret: - return ret; -} - -void adis16400_remove_trigger(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - - iio_trigger_unregister(st->trig); - free_irq(st->us->irq, st->trig); - iio_trigger_free(st->trig); -} From 1ffe2e7ac000b7a7c01b22cd64cc3d4ef01a9def Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 09/40] staging:iio:adis16400: Use triggered buffer setup helper function Use the triggered buffer helper functions to setup and tear down the buffer for the adis16400 instead of doing this manually. This also means that we switch away from the deprecated sw_ring buffer and use the kfifo buffer now instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 13 +------ drivers/staging/iio/imu/adis16400_ring.c | 47 ++++-------------------- 2 files changed, 8 insertions(+), 52 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index a948472856ed..c545cd9009fc 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -981,18 +981,10 @@ static int adis16400_probe(struct spi_device *spi) if (ret) goto error_free_dev; - ret = iio_buffer_register(indio_dev, - st->variant->channels, - st->variant->num_channels); - if (ret) { - dev_err(&spi->dev, "failed to initialize the ring\n"); - goto error_unreg_ring_funcs; - } - if (spi->irq) { ret = adis_probe_trigger(&st->adis, indio_dev); if (ret) - goto error_uninitialize_ring; + goto error_unreg_ring_funcs; } /* Get the device into a sane initial state */ @@ -1008,8 +1000,6 @@ static int adis16400_probe(struct spi_device *spi) error_remove_trigger: if (spi->irq) adis_remove_trigger(&st->adis); -error_uninitialize_ring: - iio_buffer_unregister(indio_dev); error_unreg_ring_funcs: adis16400_unconfigure_ring(indio_dev); error_free_dev: @@ -1029,7 +1019,6 @@ static int adis16400_remove(struct spi_device *spi) if (spi->irq) adis_remove_trigger(&st->adis); - iio_buffer_unregister(indio_dev); adis16400_unconfigure_ring(indio_dev); iio_device_free(indio_dev); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index 6c5b0be71900..e421278e8d79 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -7,7 +7,8 @@ #include #include -#include "../ring_sw.h" +#include +#include #include #include "adis16400.h" @@ -159,47 +160,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -void adis16400_unconfigure_ring(struct iio_dev *indio_dev) +int adis16400_configure_ring(struct iio_dev *indio_dev) { - iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &adis16400_trigger_handler, NULL); } -static const struct iio_buffer_setup_ops adis16400_ring_setup_ops = { - .preenable = &iio_sw_buffer_preenable, - .postenable = &iio_triggered_buffer_postenable, - .predisable = &iio_triggered_buffer_predisable, -}; - -int adis16400_configure_ring(struct iio_dev *indio_dev) +void adis16400_unconfigure_ring(struct iio_dev *indio_dev) { - int ret = 0; - struct iio_buffer *ring; - - ring = iio_sw_rb_allocate(indio_dev); - if (!ring) { - ret = -ENOMEM; - return ret; - } - indio_dev->buffer = ring; - ring->scan_timestamp = true; - indio_dev->setup_ops = &adis16400_ring_setup_ops; - - indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, - &adis16400_trigger_handler, - IRQF_ONESHOT, - indio_dev, - "%s_consumer%d", - indio_dev->name, - indio_dev->id); - if (indio_dev->pollfunc == NULL) { - ret = -ENOMEM; - goto error_iio_sw_rb_free; - } - - indio_dev->modes |= INDIO_BUFFER_TRIGGERED; - return 0; -error_iio_sw_rb_free: - iio_sw_rb_free(indio_dev->buffer); - return ret; + iio_triggered_buffer_cleanup(indio_dev); } From 599acfbb974dbce63c3f33f169c74fffdadcfa72 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 10/40] staging:iio:adis16400: Add helper macros for channel declaration Most of the channels declared in the adis16400 driver look quite similar. This patch adds a bunch of helper macros to initialize the channel spec for this driver. This allows us to drastically reduce the number of lines of code needed for the channel spec declaration. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 557 ++++++----------------- 1 file changed, 140 insertions(+), 417 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index c545cd9009fc..f1d747a57ea4 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -375,436 +375,159 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } } +#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 0, \ + .extend_name = name, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = (addr), \ + .scan_index = (si), \ + .scan_type = IIO_ST('u', (bits), 16, 0), \ +} + +#define ADIS16400_SUPPLY_CHAN(addr, bits) \ + ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) + +#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ + ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) + +#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = addr, \ + .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + +#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + +#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + +#define ADIS16400_MOD_TEMP_NAME_X "x" +#define ADIS16400_MOD_TEMP_NAME_Y "y" +#define ADIS16400_MOD_TEMP_NAME_Z "z" + +#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + +#define ADIS16400_TEMP_CHAN(addr, bits) { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = (addr), \ + .scan_index = ADIS16350_SCAN_TEMP_X, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + +#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ + .type = IIO_INCLI, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ + .scan_type = IIO_ST('s', (bits), 16, 0), \ +} + static const struct iio_chan_spec adis16400_channels[] = { - { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16400_SUPPLY_OUT, - .scan_index = ADIS16400_SCAN_SUPPLY, - .scan_type = IIO_ST('u', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XMAGN_OUT, - .scan_index = ADIS16400_SCAN_MAGN_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YMAGN_OUT, - .scan_index = ADIS16400_SCAN_MAGN_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_MAGN, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZMAGN_OUT, - .scan_index = ADIS16400_SCAN_MAGN_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16400_TEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_X, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16400_AUX_ADC, - .scan_index = ADIS16400_SCAN_ADC, - .scan_type = IIO_ST('s', 12, 16, 0), - }, + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), + ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), IIO_CHAN_SOFT_TIMESTAMP(12) }; static const struct iio_chan_spec adis16350_channels[] = { - { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16400_SUPPLY_OUT, - .scan_index = ADIS16400_SCAN_SUPPLY, - .scan_type = IIO_ST('u', 12, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .extend_name = "x", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16350_XTEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_X, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 1, - .extend_name = "y", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16350_YTEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_Y, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 2, - .extend_name = "z", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16350_ZTEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_Z, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16300_AUX_ADC, - .scan_index = ADIS16400_SCAN_ADC, - .scan_type = IIO_ST('s', 12, 16, 0), - }, + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), + ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), + ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), + ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), IIO_CHAN_SOFT_TIMESTAMP(11) }; static const struct iio_chan_spec adis16300_channels[] = { - { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16400_SUPPLY_OUT, - .scan_index = ADIS16400_SCAN_SUPPLY, - .scan_type = IIO_ST('u', 12, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16350_XTEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_X, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .address = ADIS16300_AUX_ADC, - .scan_index = ADIS16400_SCAN_ADC, - .scan_type = IIO_ST('s', 12, 16, 0), - }, { - .type = IIO_INCLI, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = ADIS16300_PITCH_OUT, - .scan_index = ADIS16300_SCAN_INCLI_X, - .scan_type = IIO_ST('s', 13, 16, 0), - }, { - .type = IIO_INCLI, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = ADIS16300_ROLL_OUT, - .scan_index = ADIS16300_SCAN_INCLI_Y, - .scan_type = IIO_ST('s', 13, 16, 0), - }, + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), + ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), + ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), IIO_CHAN_SOFT_TIMESTAMP(14) }; static const struct iio_chan_spec adis16334_channels[] = { - { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZGYRO_OUT, - .scan_index = ADIS16400_SCAN_GYRO_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_XACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_YACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Y, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_ACCEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, - .address = ADIS16400_ZACCL_OUT, - .scan_index = ADIS16400_SCAN_ACC_Z, - .scan_type = IIO_ST('s', 14, 16, 0), - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = ADIS16350_XTEMP_OUT, - .scan_index = ADIS16350_SCAN_TEMP_X, - .scan_type = IIO_ST('s', 14, 16, 0), - }, - IIO_CHAN_SOFT_TIMESTAMP(12) + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(8) }; static struct attribute *adis16400_attributes[] = { From 5eda3550a3cc1987a495e9f85e5998a76d15a0aa Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 11/40] staging:iio:adis16400: Preallocate transfer message Similar to like we already did for the generic adis library preallocate and pre-construct the SPI transfer message for the adis16400. For devices which do not support burst mode sampling does not differ from other adis devices and so we use the generic functions of the adis library in this case. In burst mode we can only sample all channels at once, so use the IIO cores demux facility instead of doing this manually. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400.h | 23 +-- drivers/staging/iio/imu/adis16400_core.c | 89 ++++++++--- drivers/staging/iio/imu/adis16400_ring.c | 192 +++++++---------------- 3 files changed, 128 insertions(+), 176 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index ce63ced77c7f..a3b9e56c5bd1 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -190,27 +190,14 @@ ssize_t adis16400_read_data_from_ring(struct device *dev, char *buf); -int adis16400_configure_ring(struct iio_dev *indio_dev); -void adis16400_unconfigure_ring(struct iio_dev *indio_dev); +int adis16400_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask); +irqreturn_t adis16400_trigger_handler(int irq, void *p); #else /* CONFIG_IIO_BUFFER */ -static inline ssize_t -adis16400_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return 0; -} - -static int adis16400_configure_ring(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev) -{ -} +#define adis16400_update_scan_mode NULL +#define adis16400_trigger_handler NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index f1d747a57ea4..aa4ffcfaf2a8 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -384,7 +384,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = (addr), \ .scan_index = (si), \ - .scan_type = IIO_ST('u', (bits), 16, 0), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_SUPPLY_CHAN(addr, bits) \ @@ -403,7 +409,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ .address = addr, \ .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ @@ -416,7 +428,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ .address = (addr), \ .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ @@ -428,7 +446,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ .address = (addr), \ .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_MOD_TEMP_NAME_X "x" @@ -446,7 +470,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ .address = (addr), \ .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_TEMP_CHAN(addr, bits) { \ @@ -458,7 +488,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = (addr), \ .scan_index = ADIS16350_SCAN_TEMP_X, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } #define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ @@ -469,7 +505,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = (addr), \ .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ - .scan_type = IIO_ST('s', (bits), 16, 0), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ } static const struct iio_chan_spec adis16400_channels[] = { @@ -625,6 +667,12 @@ static const struct iio_info adis16400_info = { .read_raw = &adis16400_read_raw, .write_raw = &adis16400_write_raw, .attrs = &adis16400_attribute_group, + .update_scan_mode = adis16400_update_scan_mode, +}; + +static const unsigned long adis16400_burst_scan_mask[] = { + ~0UL, + 0, }; static const char * const adis16400_status_error_msgs[] = { @@ -696,35 +744,30 @@ static int adis16400_probe(struct spi_device *spi) indio_dev->info = &adis16400_info; indio_dev->modes = INDIO_DIRECT_MODE; + if (!(st->variant->flags & ADIS16400_NO_BURST)) + indio_dev->available_scan_masks = adis16400_burst_scan_mask; + ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); if (ret) goto error_free_dev; - ret = adis16400_configure_ring(indio_dev); + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, + adis16400_trigger_handler); if (ret) goto error_free_dev; - if (spi->irq) { - ret = adis_probe_trigger(&st->adis, indio_dev); - if (ret) - goto error_unreg_ring_funcs; - } - /* Get the device into a sane initial state */ ret = adis16400_initial_setup(indio_dev); if (ret) - goto error_remove_trigger; + goto error_cleanup_buffer; ret = iio_device_register(indio_dev); if (ret) - goto error_remove_trigger; + goto error_cleanup_buffer; return 0; -error_remove_trigger: - if (spi->irq) - adis_remove_trigger(&st->adis); -error_unreg_ring_funcs: - adis16400_unconfigure_ring(indio_dev); +error_cleanup_buffer: + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); error_free_dev: iio_device_free(indio_dev); error_ret: @@ -740,9 +783,7 @@ static int adis16400_remove(struct spi_device *spi) iio_device_unregister(indio_dev); adis16400_stop_device(indio_dev); - if (spi->irq) - adis_remove_trigger(&st->adis); - adis16400_unconfigure_ring(indio_dev); + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); iio_device_free(indio_dev); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index e421278e8d79..054c01d6e73c 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -13,160 +13,84 @@ #include "adis16400.h" -/** - * adis16400_spi_read_burst() - read all data registers - * @indio_dev: the IIO device - * @rx: somewhere to pass back the value read (min size is 24 bytes) - **/ -static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx) +int adis16400_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) { - struct spi_message msg; struct adis16400_state *st = iio_priv(indio_dev); - u32 old_speed_hz = st->adis.spi->max_speed_hz; - int ret; + struct adis *adis = &st->adis; + uint16_t *tx, *rx; - struct spi_transfer xfers[] = { - { - .tx_buf = st->adis.tx, - .bits_per_word = 8, - .len = 2, - }, { - .rx_buf = rx, - .bits_per_word = 8, - .len = 24, - }, - }; - - mutex_lock(&st->adis.txrx_lock); - st->adis.tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); - st->adis.tx[1] = 0; - - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - - st->adis.spi->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz); - spi_setup(st->adis.spi); - - ret = spi_sync(st->adis.spi, &msg); - if (ret) - dev_err(&st->adis.spi->dev, "problem when burst reading"); + if (st->variant->flags & ADIS16400_NO_BURST) + return adis_update_scan_mode(indio_dev, scan_mask); - st->adis.spi->max_speed_hz = old_speed_hz; - spi_setup(st->adis.spi); - mutex_unlock(&st->adis.txrx_lock); - return ret; -} - -static const u16 read_all_tx_array[] = { - cpu_to_be16(ADIS_READ_REG(ADIS16400_SUPPLY_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_XGYRO_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_YGYRO_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_ZGYRO_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_XACCL_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_YACCL_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_ZACCL_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16350_XTEMP_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16350_YTEMP_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16350_ZTEMP_OUT)), - cpu_to_be16(ADIS_READ_REG(ADIS16400_AUX_ADC)), -}; - -static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx) -{ - struct adis16400_state *st = iio_priv(indio_dev); + kfree(adis->xfer); + kfree(adis->buffer); - struct spi_message msg; - int i, j = 0, ret; - struct spi_transfer *xfers; - int scan_count = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength); + adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); + if (!adis->xfer) + return -ENOMEM; - xfers = kzalloc(sizeof(*xfers)*(scan_count + 1), - GFP_KERNEL); - if (xfers == NULL) + adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), + GFP_KERNEL); + if (!adis->buffer) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(read_all_tx_array); i++) - if (test_bit(i, indio_dev->active_scan_mask)) { - xfers[j].tx_buf = &read_all_tx_array[i]; - xfers[j].bits_per_word = 16; - xfers[j].len = 2; - xfers[j + 1].rx_buf = rx + j*2; - j++; - } - xfers[j].bits_per_word = 16; - xfers[j].len = 2; - - spi_message_init(&msg); - for (j = 0; j < scan_count + 1; j++) - spi_message_add_tail(&xfers[j], &msg); - - ret = spi_sync(st->adis.spi, &msg); - kfree(xfers); - - return ret; + rx = adis->buffer; + tx = adis->buffer + indio_dev->scan_bytes; + + tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); + tx[1] = 0; + + adis->xfer[0].tx_buf = tx; + adis->xfer[0].bits_per_word = 8; + adis->xfer[0].len = 2; + adis->xfer[1].tx_buf = tx; + adis->xfer[1].bits_per_word = 8; + adis->xfer[1].len = indio_dev->scan_bytes; + + spi_message_init(&adis->msg); + spi_message_add_tail(&adis->xfer[0], &adis->msg); + spi_message_add_tail(&adis->xfer[1], &adis->msg); + + return 0; } -/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device - * specific to be rolled into the core. - */ -static irqreturn_t adis16400_trigger_handler(int irq, void *p) +irqreturn_t adis16400_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16400_state *st = iio_priv(indio_dev); - int i = 0, j, ret = 0; - s16 *data; - - /* Asumption that long is enough for maximum channels */ - unsigned long mask = *indio_dev->active_scan_mask; - int scan_count = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength); - data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (data == NULL) { - dev_err(&st->adis.spi->dev, "memory alloc failed in ring bh"); - goto done; + struct adis *adis = &st->adis; + u32 old_speed_hz = st->adis.spi->max_speed_hz; + int ret; + + if (!adis->buffer) + return -ENOMEM; + + if (!(st->variant->flags & ADIS16400_NO_BURST) && + st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { + st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; + spi_setup(st->adis.spi); } - if (scan_count) { - if (st->variant->flags & ADIS16400_NO_BURST) { - ret = adis16350_spi_read_all(indio_dev, st->adis.rx); - if (ret < 0) - goto done; - for (; i < scan_count; i++) - data[i] = *(s16 *)(st->adis.rx + i*2); - } else { - ret = adis16400_spi_read_burst(indio_dev, st->adis.rx); - if (ret < 0) - goto done; - for (; i < scan_count; i++) { - j = __ffs(mask); - mask &= ~(1 << j); - data[i] = be16_to_cpup( - (__be16 *)&(st->adis.rx[j*2])); - } - } + ret = spi_sync(adis->spi, &adis->msg); + if (ret) + dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); + + if (!(st->variant->flags & ADIS16400_NO_BURST)) { + st->adis.spi->max_speed_hz = old_speed_hz; + spi_setup(st->adis.spi); } + /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - iio_push_to_buffers(indio_dev, (u8 *) data); + if (indio_dev->scan_timestamp) { + void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); + *(s64 *)b = pf->timestamp; + } + + iio_push_to_buffers(indio_dev, adis->buffer); -done: - kfree(data); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } - -int adis16400_configure_ring(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &adis16400_trigger_handler, NULL); -} - -void adis16400_unconfigure_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} From 5eaf4ad9d72b619e4a171b80eaaffce69c8cf791 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 12/40] staging:iio:adis16400: Remove unit suffix from samplerate attribute To be compliant to the IIO specification we should not include the "SPS" suffix in the "samplerate" attribute contents. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index aa4ffcfaf2a8..942907276a31 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -116,7 +116,7 @@ static ssize_t adis16400_read_frequency(struct device *dev, ret = st->variant->get_freq(st); if (ret < 0) return ret; - len = sprintf(buf, "%d SPS\n", ret); + len = sprintf(buf, "%d\n", ret); return len; } From 6634ccae6f703a113a9f8515c0d8ce39706355b6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 13/40] staging:iio:adis16400: Remove samplerate_available attribute While the samplerate supported by the devices which are supported by this driver is not continuous it supports a wide range, much more than currently listed in the samplerate_available attribute. Also it accepts all values written to the samplerate attribute and will round-up them to the nearest supported sample rate. So remove the samplerate_available attribute. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 942907276a31..c08490b09151 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -247,8 +247,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16400_read_frequency, adis16400_write_frequency); -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); - static const u8 adis16400_addresses[] = { [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, @@ -574,7 +572,6 @@ static const struct iio_chan_spec adis16334_channels[] = { static struct attribute *adis16400_attributes[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; From f4c6d64bcf5b4bd868c53c6943d9b9bdd65eaa48 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 14/40] staging:iio:adis16400: Code style cleanup Do a set of minor miscellaneous code style cleanups for the adis16400 before moving it out of staging. Delete outdated comments, removed excess whitespace, add missing whitespace, replace u{8,16} with uint{8,16}_t. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/imu/adis16400_core.c | 81 +++++++++++------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index c08490b09151..1bbe5eed0139 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -45,7 +45,7 @@ enum adis16400_chip_variant { static int adis16334_get_freq(struct adis16400_state *st) { int ret; - u16 t; + uint16_t t; ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret < 0) @@ -78,12 +78,13 @@ static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) static int adis16400_get_freq(struct adis16400_state *st) { int sps, ret; - u16 t; + uint16_t t; ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret < 0) return ret; - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; + + sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; return sps; @@ -97,6 +98,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) if (t > 0) t--; t &= ADIS16400_SMPL_PRD_DIV_MASK; + if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; else @@ -111,13 +113,13 @@ static ssize_t adis16400_read_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16400_state *st = iio_priv(indio_dev); - int ret, len = 0; + int ret; ret = st->variant->get_freq(st); if (ret < 0) return ret; - len = sprintf(buf, "%d\n", ret); - return len; + + return sprintf(buf, "%d\n", ret); } static const unsigned adis16400_3db_divisors[] = { @@ -134,8 +136,8 @@ static const unsigned adis16400_3db_divisors[] = { static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) { struct adis16400_state *st = iio_priv(indio_dev); + uint16_t val16; int i, ret; - u16 val16; for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { if (sps / adis16400_3db_divisors[i] >= val) @@ -152,26 +154,22 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) } static ssize_t adis16400_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16400_state *st = iio_priv(indio_dev); long val; int ret; - ret = strict_strtol(buf, 10, &val); + ret = kstrtol(buf, 10, &val); if (ret) return ret; + if (val == 0) return -EINVAL; mutex_lock(&indio_dev->mlock); - st->variant->set_freq(st, val); - - /* Also update the filter */ mutex_unlock(&indio_dev->mlock); return ret ? ret : len; @@ -182,9 +180,9 @@ static int adis16400_stop_device(struct iio_dev *indio_dev) { struct adis16400_state *st = iio_priv(indio_dev); int ret; - u16 val = ADIS16400_SLP_CNT_POWER_OFF; - ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, val); + ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, + ADIS16400_SLP_CNT_POWER_OFF); if (ret) dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); @@ -194,10 +192,10 @@ static int adis16400_stop_device(struct iio_dev *indio_dev) static int adis16400_initial_setup(struct iio_dev *indio_dev) { - int ret; - u16 prod_id, smp_prd; - unsigned int device_id; struct adis16400_state *st = iio_priv(indio_dev); + uint16_t prod_id, smp_prd; + unsigned int device_id; + int ret; /* use low spi speed for init if the device has a slow mode */ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) @@ -224,8 +222,8 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev) device_id, prod_id); dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", - indio_dev->name, prod_id, - st->adis.spi->chip_select, st->adis.spi->irq); + indio_dev->name, prod_id, + st->adis.spi->chip_select, st->adis.spi->irq); } /* use high spi speed if possible */ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { @@ -247,7 +245,7 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16400_read_frequency, adis16400_write_frequency); -static const u8 adis16400_addresses[] = { +static const uint8_t adis16400_addresses[] = { [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, @@ -257,15 +255,12 @@ static const u8 adis16400_addresses[] = { }; static int adis16400_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); int ret, sps; - switch (mask) { + switch (info) { case IIO_CHAN_INFO_CALIBBIAS: mutex_lock(&indio_dev->mlock); ret = adis_write_reg_16(&st->adis, @@ -273,8 +268,10 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return ret; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - /* Need to cache values so we can update if the frequency - changes */ + /* + * Need to cache values so we can update if the frequency + * changes. + */ mutex_lock(&indio_dev->mlock); st->filt_int = val; /* Work out update to current value */ @@ -293,16 +290,13 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, } static int adis16400_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) + struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); + int16_t val16; int ret; - s16 val16; - switch (mask) { + switch (info) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: @@ -721,13 +715,14 @@ static const struct adis_data adis16400_data = { static int adis16400_probe(struct spi_device *spi) { - int ret; struct adis16400_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + struct iio_dev *indio_dev; + int ret; + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + st = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); @@ -767,14 +762,12 @@ static int adis16400_probe(struct spi_device *spi) adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); error_free_dev: iio_device_free(indio_dev); -error_ret: return ret; } -/* fixme, confirm ordering in this function */ static int adis16400_remove(struct spi_device *spi) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct iio_dev *indio_dev = spi_get_drvdata(spi); struct adis16400_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); From d6b09bd85d57752395c6407bd8a9b32eb7b279ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 15/40] staging:iio: Move adis16400 out of staging This adis16400 driver is in pretty good shape now, so move it out of staging. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/Kconfig | 11 +++++++++++ drivers/iio/imu/Makefile | 3 +++ drivers/{staging => }/iio/imu/adis16400.h | 0 .../imu/adis16400_buffer.c} | 0 drivers/{staging => }/iio/imu/adis16400_core.c | 0 drivers/staging/iio/Kconfig | 1 - drivers/staging/iio/Makefile | 1 - drivers/staging/iio/imu/Kconfig | 17 ----------------- drivers/staging/iio/imu/Makefile | 7 ------- 9 files changed, 14 insertions(+), 26 deletions(-) rename drivers/{staging => }/iio/imu/adis16400.h (100%) rename drivers/{staging/iio/imu/adis16400_ring.c => iio/imu/adis16400_buffer.c} (100%) rename drivers/{staging => }/iio/imu/adis16400_core.c (100%) delete mode 100644 drivers/staging/iio/imu/Kconfig delete mode 100644 drivers/staging/iio/imu/Makefile diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 3d79a40e916b..47f66ed9c4ef 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -3,6 +3,17 @@ # menu "Inertial measurement units" +config ADIS16400 + tristate "Analog Devices ADIS16400 and similar IMU SPI driver" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say yes here to build support for Analog Devices adis16300, adis16344, + adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, + adis16365, adis16400 and adis16405 triaxial inertial sensors + (adis16400 series also have magnetometers). + config ADIS16480 tristate "Analog Devices ADIS16480 and similar IMU driver" depends on SPI diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index cfe57638f6f9..019b717c5ff1 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -2,6 +2,9 @@ # Makefile for Inertial Measurement Units # +adis16400-y := adis16400_core.o +adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o +obj-$(CONFIG_ADIS16400) += adis16400.o obj-$(CONFIG_ADIS16480) += adis16480.o adis_lib-y += adis.o diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h similarity index 100% rename from drivers/staging/iio/imu/adis16400.h rename to drivers/iio/imu/adis16400.h diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/iio/imu/adis16400_buffer.c similarity index 100% rename from drivers/staging/iio/imu/adis16400_ring.c rename to drivers/iio/imu/adis16400_buffer.c diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c similarity index 100% rename from drivers/staging/iio/imu/adis16400_core.c rename to drivers/iio/imu/adis16400_core.c diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index ca56c75a35fc..94d60d5d60c8 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -32,7 +32,6 @@ source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/meter/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index fa6937d92ee3..468b7f8d2d62 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -20,7 +20,6 @@ obj-y += cdc/ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ -obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += meter/ diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig deleted file mode 100644 index 096afc8cd87e..000000000000 --- a/drivers/staging/iio/imu/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# IIO imu drivers configuration -# -menu "Inertial measurement units" - -config ADIS16400 - tristate "Analog Devices ADIS16400 and similar IMU SPI driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices adis16300, adis16344, - adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, - adis16365, adis16400 and adis16405 triaxial inertial sensors - (adis16400 series also have magnetometers). - -endmenu diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile deleted file mode 100644 index c9988f6077ff..000000000000 --- a/drivers/staging/iio/imu/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for Inertial Measurement Units -# - -adis16400-y := adis16400_core.o -adis16400-$(CONFIG_IIO_BUFFER) += adis16400_ring.o -obj-$(CONFIG_ADIS16400) += adis16400.o From b24150e31ab27ffcd2aa9b33dca42c2070526054 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 16/40] iio:adis16400: Increase samplerate precession The devices supported by this drivers support sample rates with less than one sample per second. To support this increase the samplerate precession to allow setting (and reading) the samplerate with a milli-HZ precession. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 1bbe5eed0139..8551fde90563 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -53,16 +53,15 @@ static int adis16334_get_freq(struct adis16400_state *st) t >>= ADIS16334_RATE_DIV_SHIFT; - return (8192 >> t) / 10; + return 819200 >> t; } static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) { unsigned int t; - freq *= 10; - if (freq < 8192) - t = ilog2(8192 / freq); + if (freq < 819200) + t = ilog2(819200 / freq); else t = 0; @@ -84,7 +83,7 @@ static int adis16400_get_freq(struct adis16400_state *st) if (ret < 0) return ret; - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; + sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404; sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; return sps; @@ -94,7 +93,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) { unsigned int t; - t = 1638 / freq; + t = 1638404 / freq; if (t > 0) t--; t &= ADIS16400_SMPL_PRD_DIV_MASK; @@ -119,7 +118,7 @@ static ssize_t adis16400_read_frequency(struct device *dev, if (ret < 0) return ret; - return sprintf(buf, "%d\n", ret); + return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000); } static const unsigned adis16400_3db_divisors[] = { @@ -158,14 +157,16 @@ static ssize_t adis16400_write_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16400_state *st = iio_priv(indio_dev); - long val; + int i, f, val; int ret; - ret = kstrtol(buf, 10, &val); + ret = iio_str_to_fixpoint(buf, 100, &i, &f); if (ret) return ret; - if (val == 0) + val = i * 1000 + f; + + if (val <= 0) return -EINVAL; mutex_lock(&indio_dev->mlock); @@ -281,7 +282,8 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, return sps; } - ret = adis16400_set_filter(indio_dev, sps, val); + ret = adis16400_set_filter(indio_dev, sps, + val * 1000 + val2 / 1000); mutex_unlock(&indio_dev->mlock); return ret; default: @@ -355,9 +357,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, return ret; } ret = st->variant->get_freq(st); - if (ret >= 0) - *val = ret / adis16400_3db_divisors[val16 & 0x07]; - *val2 = 0; + if (ret >= 0) { + ret /= adis16400_3db_divisors[val16 & 0x07]; + *val = ret / 1000; + *val2 = (ret % 1000) * 1000; + } mutex_unlock(&indio_dev->mlock); if (ret < 0) return ret; From 7ba8a04dcdfb5ebcb4985a92dfc4dc4f59510464 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 17/40] iio:adis16400: Add support for the 52.85 Hz base sampling rate The adis16400 and similar have two different base sampling rate available, from which the actual sampling rate is derived. 1638 Hz and 52.85 Hz, switching to the lower base sampling rate allows to support lower sampling rates. This patch adds support for switching to the lower base sampling rate if the requested sampling frequency is outside of the range which can be supported by the higher base sampling rate. The function which is used to read the current sampling rate already has support for the lower sampling rate, so no changes are required there. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 8551fde90563..58699ac22d02 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -92,18 +92,26 @@ static int adis16400_get_freq(struct adis16400_state *st) static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) { unsigned int t; + uint8_t val = 0; t = 1638404 / freq; - if (t > 0) + if (t >= 128) { + val |= ADIS16400_SMPL_PRD_TIME_BASE; + t = 52851 / freq; + if (t >= 128) + t = 127; + } else if (t != 0) { t--; - t &= ADIS16400_SMPL_PRD_DIV_MASK; + } + + val |= t; - if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) + if (t >= 0x0A || (val & ADIS16400_SMPL_PRD_TIME_BASE)) st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; else st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); + return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); } static ssize_t adis16400_read_frequency(struct device *dev, From 1db18bb4c25823bfc11f370157f9d23a4d99ea1d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 18/40] iio:adis16400: Expose some debug information in debugfs Expose some information useful for debugging a device in debugfs. This includes for now the flash count, the product id and the serial number and raw register access. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.h | 4 ++ drivers/iio/imu/adis16400_core.c | 113 +++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h index a3b9e56c5bd1..627018537aac 100644 --- a/drivers/iio/imu/adis16400.h +++ b/drivers/iio/imu/adis16400.h @@ -74,7 +74,10 @@ #define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ #define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ +#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ +#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ #define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ +#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ #define ADIS16400_ERROR_ACTIVE (1<<14) #define ADIS16400_NEW_DATA (1<<14) @@ -132,6 +135,7 @@ #define ADIS16400_HAS_PROD_ID BIT(0) #define ADIS16400_NO_BURST BIT(1) #define ADIS16400_HAS_SLOW_MODE BIT(2) +#define ADIS16400_HAS_SERIAL_NUMBER BIT(3) struct adis16400_state; diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 58699ac22d02..e8f84c9e84c6 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,104 @@ #include "adis16400.h" +#ifdef CONFIG_DEBUG_FS + +static ssize_t adis16400_show_serial_number(struct file *file, + char __user *userbuf, size_t count, loff_t *ppos) +{ + struct adis16400_state *st = file->private_data; + u16 lot1, lot2, serial_number; + char buf[16]; + size_t len; + int ret; + + ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1); + if (ret < 0) + return ret; + + ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2); + if (ret < 0) + return ret; + + ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER, + &serial_number); + if (ret < 0) + return ret; + + len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2, + serial_number); + + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations adis16400_serial_number_fops = { + .open = simple_open, + .read = adis16400_show_serial_number, + .llseek = default_llseek, + .owner = THIS_MODULE, +}; + +static int adis16400_show_product_id(void *arg, u64 *val) +{ + struct adis16400_state *st = arg; + uint16_t prod_id; + int ret; + + ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id); + if (ret < 0) + return ret; + + *val = prod_id; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops, + adis16400_show_product_id, NULL, "%lld\n"); + +static int adis16400_show_flash_count(void *arg, u64 *val) +{ + struct adis16400_state *st = arg; + uint16_t flash_count; + int ret; + + ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count); + if (ret < 0) + return ret; + + *val = flash_count; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops, + adis16400_show_flash_count, NULL, "%lld\n"); + +static int adis16400_debugfs_init(struct iio_dev *indio_dev) +{ + struct adis16400_state *st = iio_priv(indio_dev); + + if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER) + debugfs_create_file("serial_number", 0400, + indio_dev->debugfs_dentry, st, + &adis16400_serial_number_fops); + if (st->variant->flags & ADIS16400_HAS_PROD_ID) + debugfs_create_file("product_id", 0400, + indio_dev->debugfs_dentry, st, + &adis16400_product_id_fops); + debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, + st, &adis16400_flash_count_fops); + + return 0; +} + +#else + +static int adis16400_debugfs_init(struct iio_dev *indio_dev) +{ + return 0; +} + +#endif + enum adis16400_chip_variant { ADIS16300, ADIS16334, @@ -600,7 +699,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16334] = { .channels = adis16334_channels, .num_channels = ARRAY_SIZE(adis16334_channels), - .flags = ADIS16400_HAS_PROD_ID, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ .temp_scale_nano = 67850000, /* 0.06785 C */ @@ -622,7 +722,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16360] = { .channels = adis16350_channels, .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ @@ -633,7 +734,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16362] = { .channels = adis16350_channels, .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ @@ -644,7 +746,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16364] = { .channels = adis16350_channels, .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ .temp_scale_nano = 136000000, /* 0.136 C */ @@ -671,6 +774,7 @@ static const struct iio_info adis16400_info = { .write_raw = &adis16400_write_raw, .attrs = &adis16400_attribute_group, .update_scan_mode = adis16400_update_scan_mode, + .debugfs_reg_access = adis_debugfs_reg_access, }; static const unsigned long adis16400_burst_scan_mask[] = { @@ -768,6 +872,7 @@ static int adis16400_probe(struct spi_device *spi) if (ret) goto error_cleanup_buffer; + adis16400_debugfs_init(indio_dev); return 0; error_cleanup_buffer: From 76ada52f7f5d4c83cbb6d61e556e3fbd0ac6d34f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: [PATCH 19/40] iio:adis16400: Add support for the adis16448 The adis16448 is more or less from the same family of devices as supported by this driver. It features three acceleration channels, three angular velocity channels, three magnetometer channels, one temperature channels and one barometric pressure channel. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.h | 4 ++++ drivers/iio/imu/adis16400_core.c | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h index 627018537aac..2f8f9d632386 100644 --- a/drivers/iio/imu/adis16400.h +++ b/drivers/iio/imu/adis16400.h @@ -44,6 +44,9 @@ #define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ #define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ +#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ +#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ + /* Calibration parameters */ #define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ #define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ @@ -179,6 +182,7 @@ enum { ADIS16400_SCAN_MAGN_X, ADIS16400_SCAN_MAGN_Y, ADIS16400_SCAN_MAGN_Z, + ADIS16400_SCAN_BARO, ADIS16350_SCAN_TEMP_X, ADIS16350_SCAN_TEMP_Y, ADIS16350_SCAN_TEMP_Z, diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index e8f84c9e84c6..b7f215eab5de 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -139,6 +139,7 @@ enum adis16400_chip_variant { ADIS16362, ADIS16364, ADIS16400, + ADIS16448, }; static int adis16334_get_freq(struct adis16400_state *st) @@ -633,6 +634,28 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(12) }; +static const struct iio_chan_spec adis16448_channels[] = { + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 16), + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 16), + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16), + { + .type = IIO_PRESSURE, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = ADIS16448_BARO_OUT, + .scan_index = ADIS16400_SCAN_BARO, + .scan_type = IIO_ST('s', 16, 16, 0), + }, + ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(11) +}; + static const struct iio_chan_spec adis16350_channels[] = { ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), @@ -765,6 +788,18 @@ static struct adis16400_chip_info adis16400_chips[] = { .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, + }, + [ADIS16448] = { + .channels = adis16448_channels, + .num_channels = ARRAY_SIZE(adis16448_channels), + .flags = ADIS16400_HAS_PROD_ID | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, } }; @@ -909,6 +944,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16365", ADIS16360}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, + {"adis16448", ADIS16448}, {} }; MODULE_DEVICE_TABLE(spi, adis16400_id); From a819a0df8ab6e9425cb8d038424f4e7c5c9d77cd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 30 Nov 2012 14:22:00 +0000 Subject: [PATCH 20/40] staging:iio:accel:lis3l02dq remove sw_ring support. The sw_ring buffer is being removed in favour of the kfifo version. This is one of only a couple of driver still supporting its use. This driver will hopefully also be removed in favour of supporting the part in the unified ST accelerometer driver. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/Kconfig | 23 +--------------------- drivers/staging/iio/accel/lis3l02dq.h | 8 -------- drivers/staging/iio/accel/lis3l02dq_ring.c | 7 +++---- 3 files changed, 4 insertions(+), 34 deletions(-) diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 2b54430f2d99..fa772a9fb612 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -67,34 +67,13 @@ config LIS3L02DQ tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver" depends on SPI select IIO_TRIGGER if IIO_BUFFER - depends on !IIO_BUFFER || IIO_KFIFO_BUF || IIO_SW_RING + depends on !IIO_BUFFER || IIO_KFIFO_BUF depends on GENERIC_GPIO help Say yes here to build SPI support for the ST microelectronics accelerometer. The driver supplies direct access via sysfs files and an event interface via a character device. -choice - prompt "Buffer type" - depends on LIS3L02DQ && IIO_BUFFER - -config LIS3L02DQ_BUF_KFIFO - depends on IIO_KFIFO_BUF - bool "Simple FIFO" - help - Kfifo based FIFO. Does not provide any events so it is up - to userspace to ensure it reads often enough that data is not - lost. - -config LIS3L02DQ_BUF_RING_SW - depends on IIO_SW_RING - bool "IIO Software Ring" - help - Original IIO ring buffer implementation. Provides simple - buffer events, half full etc. - -endchoice - config SCA3000 depends on IIO_BUFFER depends on SPI diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index 2bac7221837c..0a8ea8270866 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -185,14 +185,6 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev); int lis3l02dq_configure_buffer(struct iio_dev *indio_dev); void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev); -#ifdef CONFIG_LIS3L02DQ_BUF_RING_SW -#define lis3l02dq_free_buf iio_sw_rb_free -#define lis3l02dq_alloc_buf iio_sw_rb_allocate -#endif -#ifdef CONFIG_LIS3L02DQ_BUF_KFIFO -#define lis3l02dq_free_buf iio_kfifo_free -#define lis3l02dq_alloc_buf iio_kfifo_allocate -#endif irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private); #define lis3l02dq_th lis3l02dq_data_rdy_trig_poll diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index bc38651c315e..6861877c3914 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -7,7 +7,6 @@ #include #include -#include "../ring_sw.h" #include #include #include @@ -318,7 +317,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - lis3l02dq_free_buf(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } static int lis3l02dq_buffer_postenable(struct iio_dev *indio_dev) @@ -401,7 +400,7 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) int ret; struct iio_buffer *buffer; - buffer = lis3l02dq_alloc_buf(indio_dev); + buffer = iio_kfifo_allocate(indio_dev); if (!buffer) return -ENOMEM; @@ -427,6 +426,6 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) return 0; error_iio_sw_rb_free: - lis3l02dq_free_buf(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); return ret; } From 032658a446145b9e6af7f90521179a9e0111b546 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 30 Nov 2012 14:22:00 +0000 Subject: [PATCH 21/40] staging:iio:impedance-analyzer switch from sw_ring to kfifo. sw_ring buffer implementation is going away so switch to the kfifo based alternative. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/Kconfig | 2 +- drivers/staging/iio/impedance-analyzer/ad5933.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/iio/impedance-analyzer/Kconfig b/drivers/staging/iio/impedance-analyzer/Kconfig index ad0ff765e4b2..dd97b6bb3fd0 100644 --- a/drivers/staging/iio/impedance-analyzer/Kconfig +++ b/drivers/staging/iio/impedance-analyzer/Kconfig @@ -7,7 +7,7 @@ config AD5933 tristate "Analog Devices AD5933, AD5934 driver" depends on I2C select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF help Say yes here to build support for Analog Devices Impedance Converter, Network Analyzer, AD5933/4, provides direct access via sysfs. diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 779243d24dec..440e2261e8cb 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -22,7 +22,7 @@ #include #include #include -#include "../ring_sw.h" +#include #include "ad5933.h" @@ -630,7 +630,7 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = { static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) { - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) return -ENOMEM; @@ -774,7 +774,7 @@ static int ad5933_probe(struct i2c_client *client, error_uninitialize_ring: iio_buffer_unregister(indio_dev); error_unreg_ring: - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -794,7 +794,7 @@ static int ad5933_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_buffer_unregister(indio_dev); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); if (!IS_ERR(st->reg)) { regulator_disable(st->reg); regulator_put(st->reg); From 94f3c7cd829319317a95649cd43abb07c188c191 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 30 Nov 2012 14:22:00 +0000 Subject: [PATCH 22/40] staging:iio:meter:ade7758 switch from sw_ring to kfifo sw ring is going away so switch over to kfifo based buffer implementation. The only real change is that poll will return on some data there rather than buffer 50% full. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/Kconfig | 2 +- drivers/staging/iio/meter/ade7758_ring.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index d290d2738419..e53274b64ae1 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -21,7 +21,7 @@ config ADE7758 tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver" depends on SPI select IIO_TRIGGER if IIO_BUFFER - select IIO_SW_RING if IIO_BUFFER + select IIO_KFIFO_BUF if IIO_BUFFER help Say yes here to build support for Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC with Per Phase Information Driver. diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 4552a4c7fe33..b29e2d5d9937 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -13,7 +13,7 @@ #include #include -#include "../ring_sw.h" +#include #include #include "ade7758.h" @@ -119,7 +119,7 @@ static const struct iio_buffer_setup_ops ade7758_ring_setup_ops = { void ade7758_unconfigure_ring(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } int ade7758_configure_ring(struct iio_dev *indio_dev) @@ -127,7 +127,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) struct ade7758_state *st = iio_priv(indio_dev); int ret = 0; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; return ret; @@ -143,7 +143,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_iio_sw_rb_free; + goto error_iio_kfifo_free; } indio_dev->modes |= INDIO_BUFFER_TRIGGERED; @@ -183,8 +183,8 @@ int ade7758_configure_ring(struct iio_dev *indio_dev) return 0; -error_iio_sw_rb_free: - iio_sw_rb_free(indio_dev->buffer); +error_iio_kfifo_free: + iio_kfifo_free(indio_dev->buffer); return ret; } From df2e8f78e7fe749332f82dcba6438fc2b3016a96 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 30 Nov 2012 14:22:00 +0000 Subject: [PATCH 23/40] staging:iio: drop sw_ring buffer implementation. Whilst this is IIO's oldest buffer implementation it is messy, poorly implemented and whilst it works, no one is entirely sure it always will. New IIO drivers have not been using this for some time and now all remaining old users have been converted to use the kfifo based alternative. Clearly a fifo isn't the same as a ring buffer but in many use cases it really doesn't matter. We also loose the watershed based poll implementation. However having poll effectively report data only when the buffer was half full was at best an 'unusual' use of the interface. At somepoint in the future we may bring watersheds back on a different buffer implementation, but then we will think a lot more about how to do the interface first. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Kconfig | 13 -- drivers/staging/iio/Makefile | 2 - drivers/staging/iio/ring_sw.c | 366 ---------------------------------- drivers/staging/iio/ring_sw.h | 30 --- 4 files changed, 411 deletions(-) delete mode 100644 drivers/staging/iio/ring_sw.c delete mode 100644 drivers/staging/iio/ring_sw.h diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 94d60d5d60c8..dc267175a2b5 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -12,19 +12,6 @@ config IIO_ST_HWMON map allows IIO devices to provide basic hwmon functionality for those channels specified in the map. -if IIO_BUFFER - -config IIO_SW_RING - select IIO_TRIGGER - tristate "Industrial I/O lock free software ring" - help - Example software ring buffer implementation. The design aim - of this particular realization was to minimize write locking - with the intention that some devices would be able to write - in interrupt context. - -endif # IIO_BUFFER - source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 468b7f8d2d62..158e0a017e7b 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -2,8 +2,6 @@ # Makefile for the industrial I/O core. # -obj-$(CONFIG_IIO_SW_RING) += ring_sw.o - obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o iio_dummy-y := iio_simple_dummy.o iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c deleted file mode 100644 index 3a45f9a52de8..000000000000 --- a/drivers/staging/iio/ring_sw.c +++ /dev/null @@ -1,366 +0,0 @@ -/* The industrial I/O simple minimally locked ring buffer. - * - * Copyright (c) 2008 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ring_sw.h" -#include - -/** - * struct iio_sw_ring_buffer - software ring buffer - * @buf: generic ring buffer elements - * @data: the ring buffer memory - * @read_p: read pointer (oldest available) - * @write_p: write pointer - * @half_p: half buffer length behind write_p (event generation) - * @update_needed: flag to indicate change in size requested - * - * Note that the first element of all ring buffers must be a - * struct iio_buffer. -**/ -struct iio_sw_ring_buffer { - struct iio_buffer buf; - unsigned char *data; - unsigned char *read_p; - unsigned char *write_p; - /* used to act as a point at which to signal an event */ - unsigned char *half_p; - int update_needed; -}; - -#define iio_to_sw_ring(r) container_of(r, struct iio_sw_ring_buffer, buf) - -static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, - int bytes_per_datum, int length) -{ - if ((length == 0) || (bytes_per_datum == 0)) - return -EINVAL; - __iio_update_buffer(&ring->buf, bytes_per_datum, length); - ring->data = kmalloc(length*ring->buf.bytes_per_datum, GFP_ATOMIC); - ring->read_p = NULL; - ring->write_p = NULL; - ring->half_p = NULL; - return ring->data ? 0 : -ENOMEM; -} - -static inline void __iio_free_sw_ring_buffer(struct iio_sw_ring_buffer *ring) -{ - kfree(ring->data); -} - -/* Ring buffer related functionality */ -/* Store to ring is typically called in the bh of a data ready interrupt handler - * in the device driver */ -/* Lock always held if their is a chance this may be called */ -/* Only one of these per ring may run concurrently - enforced by drivers */ -static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, - unsigned char *data) -{ - int ret = 0; - unsigned char *temp_ptr, *change_test_ptr; - - /* initial store */ - if (unlikely(ring->write_p == NULL)) { - ring->write_p = ring->data; - /* Doesn't actually matter if this is out of the set - * as long as the read pointer is valid before this - * passes it - guaranteed as set later in this function. - */ - ring->half_p = ring->data - ring->buf.length*ring->buf.bytes_per_datum/2; - } - /* Copy data to where ever the current write pointer says */ - memcpy(ring->write_p, data, ring->buf.bytes_per_datum); - barrier(); - /* Update the pointer used to get most recent value. - * Always valid as either points to latest or second latest value. - * Before this runs it is null and read attempts fail with -EAGAIN. - */ - barrier(); - /* temp_ptr used to ensure we never have an invalid pointer - * it may be slightly lagging, but never invalid - */ - temp_ptr = ring->write_p + ring->buf.bytes_per_datum; - /* End of ring, back to the beginning */ - if (temp_ptr == ring->data + ring->buf.length*ring->buf.bytes_per_datum) - temp_ptr = ring->data; - /* Update the write pointer - * always valid as long as this is the only function able to write. - * Care needed with smp systems to ensure more than one ring fill - * is never scheduled. - */ - ring->write_p = temp_ptr; - - if (ring->read_p == NULL) - ring->read_p = ring->data; - /* Buffer full - move the read pointer and create / escalate - * ring event */ - /* Tricky case - if the read pointer moves before we adjust it. - * Handle by not pushing if it has moved - may result in occasional - * unnecessary buffer full events when it wasn't quite true. - */ - else if (ring->write_p == ring->read_p) { - change_test_ptr = ring->read_p; - temp_ptr = change_test_ptr + ring->buf.bytes_per_datum; - if (temp_ptr - == ring->data + ring->buf.length*ring->buf.bytes_per_datum) { - temp_ptr = ring->data; - } - /* We are moving pointer on one because the ring is full. Any - * change to the read pointer will be this or greater. - */ - if (change_test_ptr == ring->read_p) - ring->read_p = temp_ptr; - } - /* investigate if our event barrier has been passed */ - /* There are definite 'issues' with this and chances of - * simultaneous read */ - /* Also need to use loop count to ensure this only happens once */ - ring->half_p += ring->buf.bytes_per_datum; - if (ring->half_p == ring->data + ring->buf.length*ring->buf.bytes_per_datum) - ring->half_p = ring->data; - if (ring->half_p == ring->read_p) { - ring->buf.stufftoread = true; - wake_up_interruptible(&ring->buf.pollq); - } - return ret; -} - -static int iio_read_first_n_sw_rb(struct iio_buffer *r, - size_t n, char __user *buf) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - - u8 *initial_read_p, *initial_write_p, *current_read_p, *end_read_p; - u8 *data; - int ret, max_copied, bytes_to_rip, dead_offset; - size_t data_available, buffer_size; - - /* A userspace program has probably made an error if it tries to - * read something that is not a whole number of bpds. - * Return an error. - */ - if (n % ring->buf.bytes_per_datum) { - ret = -EINVAL; - printk(KERN_INFO "Ring buffer read request not whole number of" - "samples: Request bytes %zd, Current bytes per datum %d\n", - n, ring->buf.bytes_per_datum); - goto error_ret; - } - - buffer_size = ring->buf.bytes_per_datum*ring->buf.length; - - /* Limit size to whole of ring buffer */ - bytes_to_rip = min_t(size_t, buffer_size, n); - - data = kmalloc(bytes_to_rip, GFP_KERNEL); - if (data == NULL) { - ret = -ENOMEM; - goto error_ret; - } - - /* build local copy */ - initial_read_p = ring->read_p; - if (unlikely(initial_read_p == NULL)) { /* No data here as yet */ - ret = 0; - goto error_free_data_cpy; - } - - initial_write_p = ring->write_p; - - /* Need a consistent pair */ - while ((initial_read_p != ring->read_p) - || (initial_write_p != ring->write_p)) { - initial_read_p = ring->read_p; - initial_write_p = ring->write_p; - } - if (initial_write_p == initial_read_p) { - /* No new data available.*/ - ret = 0; - goto error_free_data_cpy; - } - - if (initial_write_p >= initial_read_p) - data_available = initial_write_p - initial_read_p; - else - data_available = buffer_size - (initial_read_p - initial_write_p); - - if (data_available < bytes_to_rip) - bytes_to_rip = data_available; - - if (initial_read_p + bytes_to_rip >= ring->data + buffer_size) { - max_copied = ring->data + buffer_size - initial_read_p; - memcpy(data, initial_read_p, max_copied); - memcpy(data + max_copied, ring->data, bytes_to_rip - max_copied); - end_read_p = ring->data + bytes_to_rip - max_copied; - } else { - memcpy(data, initial_read_p, bytes_to_rip); - end_read_p = initial_read_p + bytes_to_rip; - } - - /* Now to verify which section was cleanly copied - i.e. how far - * read pointer has been pushed */ - current_read_p = ring->read_p; - - if (initial_read_p <= current_read_p) - dead_offset = current_read_p - initial_read_p; - else - dead_offset = buffer_size - (initial_read_p - current_read_p); - - /* possible issue if the initial write has been lapped or indeed - * the point we were reading to has been passed */ - /* No valid data read. - * In this case the read pointer is already correct having been - * pushed further than we would look. */ - if (bytes_to_rip - dead_offset < 0) { - ret = 0; - goto error_free_data_cpy; - } - - /* setup the next read position */ - /* Beware, this may fail due to concurrency fun and games. - * Possible that sufficient fill commands have run to push the read - * pointer past where we would be after the rip. If this occurs, leave - * it be. - */ - /* Tricky - deal with loops */ - - while (ring->read_p != end_read_p) - ring->read_p = end_read_p; - - ret = bytes_to_rip - dead_offset; - - if (copy_to_user(buf, data + dead_offset, ret)) { - ret = -EFAULT; - goto error_free_data_cpy; - } - - if (bytes_to_rip >= ring->buf.length*ring->buf.bytes_per_datum/2) - ring->buf.stufftoread = 0; - -error_free_data_cpy: - kfree(data); -error_ret: - - return ret; -} - -static int iio_store_to_sw_rb(struct iio_buffer *r, - u8 *data) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - return iio_store_to_sw_ring(ring, data); -} - -static int iio_request_update_sw_rb(struct iio_buffer *r) -{ - int ret = 0; - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - - r->stufftoread = false; - if (!ring->update_needed) - goto error_ret; - __iio_free_sw_ring_buffer(ring); - ret = __iio_allocate_sw_ring_buffer(ring, ring->buf.bytes_per_datum, - ring->buf.length); -error_ret: - return ret; -} - -static int iio_get_bytes_per_datum_sw_rb(struct iio_buffer *r) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - return ring->buf.bytes_per_datum; -} - -static int iio_mark_update_needed_sw_rb(struct iio_buffer *r) -{ - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - ring->update_needed = true; - return 0; -} - -static int iio_set_bytes_per_datum_sw_rb(struct iio_buffer *r, size_t bpd) -{ - if (r->bytes_per_datum != bpd) { - r->bytes_per_datum = bpd; - iio_mark_update_needed_sw_rb(r); - } - return 0; -} - -static int iio_get_length_sw_rb(struct iio_buffer *r) -{ - return r->length; -} - -static int iio_set_length_sw_rb(struct iio_buffer *r, int length) -{ - if (r->length != length) { - r->length = length; - iio_mark_update_needed_sw_rb(r); - } - return 0; -} - -static IIO_BUFFER_ENABLE_ATTR; -static IIO_BUFFER_LENGTH_ATTR; - -/* Standard set of ring buffer attributes */ -static struct attribute *iio_ring_attributes[] = { - &dev_attr_length.attr, - &dev_attr_enable.attr, - NULL, -}; - -static struct attribute_group iio_ring_attribute_group = { - .attrs = iio_ring_attributes, - .name = "buffer", -}; - -static const struct iio_buffer_access_funcs ring_sw_access_funcs = { - .store_to = &iio_store_to_sw_rb, - .read_first_n = &iio_read_first_n_sw_rb, - .request_update = &iio_request_update_sw_rb, - .get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb, - .set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb, - .get_length = &iio_get_length_sw_rb, - .set_length = &iio_set_length_sw_rb, -}; - -struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev) -{ - struct iio_buffer *buf; - struct iio_sw_ring_buffer *ring; - - ring = kzalloc(sizeof *ring, GFP_KERNEL); - if (!ring) - return NULL; - ring->update_needed = true; - buf = &ring->buf; - iio_buffer_init(buf); - buf->attrs = &iio_ring_attribute_group; - buf->access = &ring_sw_access_funcs; - - return buf; -} -EXPORT_SYMBOL(iio_sw_rb_allocate); - -void iio_sw_rb_free(struct iio_buffer *r) -{ - kfree(iio_to_sw_ring(r)); -} -EXPORT_SYMBOL(iio_sw_rb_free); - -MODULE_DESCRIPTION("Industrial I/O software ring buffer"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h deleted file mode 100644 index a5857aa7aefa..000000000000 --- a/drivers/staging/iio/ring_sw.h +++ /dev/null @@ -1,30 +0,0 @@ -/* The industrial I/O simple minimally locked ring buffer. - * - * Copyright (c) 2008 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. - * - * This code is deliberately kept separate from the main industrialio I/O core - * as it is intended that in the future a number of different software ring - * buffer implementations will exist with different characteristics to suit - * different applications. - * - * This particular one was designed for a data capture application where it was - * particularly important that no userspace reads would interrupt the capture - * process. To this end the ring is not locked during a read. - * - * Comments on this buffer design welcomed. It's far from efficient and some of - * my understanding of the effects of scheduling on this are somewhat limited. - * Frankly, to my mind, this is the current weak point in the industrial I/O - * patch set. - */ - -#ifndef _IIO_RING_SW_H_ -#define _IIO_RING_SW_H_ -#include - -struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev); -void iio_sw_rb_free(struct iio_buffer *ring); -#endif /* _IIO_RING_SW_H_ */ From b775dce99621af52d32c1d7335cf94eee4383e8a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 17 Jan 2013 01:49:00 +0000 Subject: [PATCH 24/40] rtc: hid-sensor-time: Add missing spin_lock_init Signed-off-by: Axel Lin Acked-by: Alexander Holler Signed-off-by: Jonathan Cameron --- drivers/rtc/rtc-hid-sensor-time.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 0438c9ee9a3b..31c5728ef629 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -225,6 +225,7 @@ static int hid_time_probe(struct platform_device *pdev) platform_set_drvdata(pdev, time_state); + spin_lock_init(&time_state->lock_last_time); init_completion(&time_state->comp_last_time); time_state->common_attributes.hsdev = hsdev; time_state->common_attributes.pdev = pdev; From d526e513c7dd1bb3f9696c7d38634e5ebf5f0919 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Jan 2013 15:10:00 +0000 Subject: [PATCH 25/40] staging:iio:accel:kxsd9 Remove an unneeded initialization and trivial reorder to ensure the device is ready when the device is registered. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/kxsd9.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c index 318331f08d9c..4a24c2ee81a9 100644 --- a/drivers/staging/iio/accel/kxsd9.c +++ b/drivers/staging/iio/accel/kxsd9.c @@ -226,7 +226,7 @@ static int kxsd9_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct kxsd9_state *st; - int ret = 0; + int ret; indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { @@ -245,14 +245,14 @@ static int kxsd9_probe(struct spi_device *spi) indio_dev->info = &kxsd9_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - spi->mode = SPI_MODE_0; spi_setup(spi); kxsd9_power_up(st); + ret = iio_device_register(indio_dev); + if (ret) + goto error_free_dev; + return 0; error_free_dev: From 81ca486fe54c799033fac1eb6d93baf64df37ba6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Jan 2013 15:10:00 +0000 Subject: [PATCH 26/40] iio:accel:kxsd9 move out of staging This is a very simple driver giving basic access to this part over an spi bus. Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 7 +++++++ drivers/iio/accel/Makefile | 1 + drivers/{staging => }/iio/accel/kxsd9.c | 0 drivers/staging/iio/accel/Kconfig | 7 ------- drivers/staging/iio/accel/Makefile | 2 -- 5 files changed, 8 insertions(+), 9 deletions(-) rename drivers/{staging => }/iio/accel/kxsd9.c (100%) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 05e996fafc9d..d6003531bd63 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -14,4 +14,11 @@ config HID_SENSOR_ACCEL_3D Say yes here to build support for the HID SENSOR accelerometers 3D. +config KXSD9 + tristate "Kionix KXSD9 Accelerometer Driver" + depends on SPI + help + Say yes here to build support for the Kionix KXSD9 accelerometer. + Currently this only supports the device via an SPI interface. + endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 5bc6855a973e..4e1c85987d13 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o +obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c similarity index 100% rename from drivers/staging/iio/accel/kxsd9.c rename to drivers/iio/accel/kxsd9.c diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index fa772a9fb612..e2e786dc9c7b 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -56,13 +56,6 @@ config ADIS16240 Say yes here to build support for Analog Devices adis16240 programmable impact Sensor and recorder. -config KXSD9 - tristate "Kionix KXSD9 Accelerometer Driver" - depends on SPI - help - Say yes here to build support for the Kionix KXSD9 accelerometer. - Currently this only supports the device via an SPI interface. - config LIS3L02DQ tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver" depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 8e7ee0368519..1ed137f1a506 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -20,8 +20,6 @@ obj-$(CONFIG_ADIS16220) += adis16220.o adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o -obj-$(CONFIG_KXSD9) += kxsd9.o - lis3l02dq-y := lis3l02dq_core.o lis3l02dq-$(CONFIG_IIO_BUFFER) += lis3l02dq_ring.o obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o From 232827fb8168d07844a589f0d4991afab16a23ea Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Mon, 21 Jan 2013 21:14:00 +0000 Subject: [PATCH 27/40] staging/iio: Use correct argument for sizeof found with coccicheck sizeof when applied to a pointer typed expression gives the size of the pointer The semantic patch that makes this output is available in scripts/coccinelle/misc/noderef.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Peter Huewe Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c index c7a5f97576c7..97ad645bb15a 100644 --- a/drivers/staging/iio/iio_hwmon.c +++ b/drivers/staging/iio/iio_hwmon.c @@ -93,7 +93,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) while (st->channels[st->num_channels].indio_dev) st->num_channels++; - st->attrs = kzalloc(sizeof(st->attrs) * (st->num_channels + 1), + st->attrs = kzalloc(sizeof(*st->attrs) * (st->num_channels + 1), GFP_KERNEL); if (st->attrs == NULL) { ret = -ENOMEM; From 5e1f9aca0a8f8696a97cb1637b3f7eb89688e393 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 21 Jan 2013 20:05:00 +0000 Subject: [PATCH 28/40] iio: mxs: Add MX23 support into the IIO driver This patch adds support for i.MX23 into the LRADC driver. The LRADC block on MX23 is not much different from the one on MX28, thus this is only a few changes fixing the parts that are specific to MX23. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Jonathan Cameron Cc: Shawn Guo Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/Kconfig | 4 +-- drivers/staging/iio/adc/mxs-lradc.c | 56 ++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index fb8c239b0c88..7b2a01d64f5e 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -119,12 +119,12 @@ config LPC32XX_ADC via sysfs. config MXS_LRADC - tristate "Freescale i.MX28 LRADC" + tristate "Freescale i.MX23/i.MX28 LRADC" depends on ARCH_MXS select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for i.MX28 LRADC convertor + Say yes here to build support for i.MX23/i.MX28 LRADC convertor built into these chips. To compile this driver as a module, choose M here: the diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index e4728712a1ad..b1b8c42a1c2a 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -76,7 +76,24 @@ */ #define LRADC_TS_SAMPLE_AMOUNT 4 -static const char * const mxs_lradc_irq_name[] = { +enum mxs_lradc_id { + IMX23_LRADC, + IMX28_LRADC, +}; + +static const char * const mx23_lradc_irq_names[] = { + "mxs-lradc-touchscreen", + "mxs-lradc-channel0", + "mxs-lradc-channel1", + "mxs-lradc-channel2", + "mxs-lradc-channel3", + "mxs-lradc-channel4", + "mxs-lradc-channel5", + "mxs-lradc-channel6", + "mxs-lradc-channel7", +}; + +static const char * const mx28_lradc_irq_names[] = { "mxs-lradc-touchscreen", "mxs-lradc-thresh0", "mxs-lradc-thresh1", @@ -92,6 +109,22 @@ static const char * const mxs_lradc_irq_name[] = { "mxs-lradc-button1", }; +struct mxs_lradc_of_config { + const int irq_count; + const char * const *irq_name; +}; + +static const struct mxs_lradc_of_config const mxs_lradc_of_config[] = { + [IMX23_LRADC] = { + .irq_count = ARRAY_SIZE(mx23_lradc_irq_names), + .irq_name = mx23_lradc_irq_names, + }, + [IMX28_LRADC] = { + .irq_count = ARRAY_SIZE(mx28_lradc_irq_names), + .irq_name = mx28_lradc_irq_names, + }, +}; + enum mxs_lradc_ts { MXS_LRADC_TOUCHSCREEN_NONE = 0, MXS_LRADC_TOUCHSCREEN_4WIRE, @@ -857,8 +890,19 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) writel(0, lradc->base + LRADC_DELAY(i)); } +static const struct of_device_id mxs_lradc_dt_ids[] = { + { .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, }, + { .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids); + static int mxs_lradc_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(mxs_lradc_dt_ids, &pdev->dev); + const struct mxs_lradc_of_config *of_cfg = + &mxs_lradc_of_config[(enum mxs_lradc_id)of_id->data]; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct mxs_lradc *lradc; @@ -902,7 +946,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) ts_wires); /* Grab all IRQ sources */ - for (i = 0; i < 13; i++) { + for (i = 0; i < of_cfg->irq_count; i++) { lradc->irq[i] = platform_get_irq(pdev, i); if (lradc->irq[i] < 0) { ret = -EINVAL; @@ -911,7 +955,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, lradc->irq[i], mxs_lradc_handle_irq, 0, - mxs_lradc_irq_name[i], iio); + of_cfg->irq_name[i], iio); if (ret) goto err_addr; } @@ -983,12 +1027,6 @@ static int mxs_lradc_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id mxs_lradc_dt_ids[] = { - { .compatible = "fsl,imx28-lradc", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids); - static struct platform_driver mxs_lradc_driver = { .driver = { .name = DRIVER_NAME, From 1f45188c40432843825865582ace8d118f9ed407 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 21 Jan 2013 20:05:00 +0000 Subject: [PATCH 29/40] ARM: mxs: Add OF props for MX23 LRADC Add interrupt mapping and compatible string for MX23 LRADC. Signed-off-by: Marek Vasut Cc: Fabio Estevam Acked-by: Shawn Guo Signed-off-by: Jonathan Cameron --- arch/arm/boot/dts/imx23.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 65415c598a5e..56afcf41aae0 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -391,7 +391,9 @@ }; lradc@80050000 { + compatible = "fsl,imx23-lradc"; reg = <0x80050000 0x2000>; + interrupts = <36 37 38 39 40 41 42 43 44>; status = "disabled"; }; From c21ab7005140bdc5898907f73a5d73a86ea60a5d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 30/40] staging:iio:adis16080: Add device id table entry for the adis16100 The adis16100 is very similar to the adis16080. The driver description already states that the driver supports the adis16100 as-well. But so far the there is no device id table for the adis16100 and the drivers does not bind to a device named adis16100. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/Kconfig | 4 ++-- drivers/staging/iio/gyro/adis16080_core.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index 87979a0d03a9..a439e0512d5a 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -14,8 +14,8 @@ config ADIS16080 tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver" depends on SPI help - Say yes here to build support for Analog Devices adis16080/100 Yaw Rate - Gyroscope with SPI. + Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw + Rate Gyroscope with SPI. config ADIS16130 tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver" diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 41d7350d030f..2eb559cff347 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -185,6 +185,13 @@ static int adis16080_remove(struct spi_device *spi) return 0; } +static const struct spi_device_id adis16080_ids[] = { + { "adis16080", 0 }, + { "adis16100", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(spi, adis16080_ids); + static struct spi_driver adis16080_driver = { .driver = { .name = "adis16080", @@ -192,10 +199,10 @@ static struct spi_driver adis16080_driver = { }, .probe = adis16080_probe, .remove = adis16080_remove, + .id_table = adis16080_ids, }; module_spi_driver(adis16080_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16080"); From 9ab82f071125e340a052570df90813b11574f8d4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 31/40] staging:iio:adis16080: Cleanup SPI transfer During sampling the driver currently does a spi_read followed by a spi_write. This is not a problem per se, since CS needs to be deasserted between the two transfers. So even if another device claims the bus between the two transfers we should still get a result. But the code is actually spread out over multiple functions. E.g. the spi_read happens in one function the spi_write in another, this makes the code harder to follow. This patch re-factors the code to just use a single spi transaction to do both the read and the write transfer. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/adis16080_core.c | 61 ++++++++++------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 2eb559cff347..ddeae163982a 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -42,32 +42,32 @@ struct adis16080_state { u8 buf[2] ____cacheline_aligned; }; -static int adis16080_spi_write(struct iio_dev *indio_dev, - u16 val) +static int adis16080_read_sample(struct iio_dev *indio_dev, + u16 addr, int *val) { - int ret; struct adis16080_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->buf[0] = val >> 8; - st->buf[1] = val; - - ret = spi_write(st->us, st->buf, 2); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int adis16080_spi_read(struct iio_dev *indio_dev, - u16 *val) -{ + struct spi_message m; int ret; - struct adis16080_state *st = iio_priv(indio_dev); + struct spi_transfer t[] = { + { + .tx_buf = &st->buf, + .len = 2, + .cs_change = 1, + }, { + .rx_buf = &st->buf, + .len = 2, + }, + }; mutex_lock(&st->buf_lock); + st->buf[0] = addr >> 8; + st->buf[1] = addr; - ret = spi_read(st->us, st->buf, 2); + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + ret = spi_sync(st->us, &m); if (ret == 0) *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11); mutex_unlock(&st->buf_lock); @@ -81,28 +81,17 @@ static int adis16080_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { - int ret = -EINVAL; - u16 ut = 0; - /* Take the iio_dev status lock */ + int ret; - mutex_lock(&indio_dev->mlock); switch (mask) { case IIO_CHAN_INFO_RAW: - ret = adis16080_spi_write(indio_dev, - chan->address | - ADIS16080_DIN_WRITE); - if (ret < 0) - break; - ret = adis16080_spi_read(indio_dev, &ut); - if (ret < 0) - break; - *val = ut; - ret = IIO_VAL_INT; - break; + mutex_lock(&indio_dev->mlock); + ret = adis16080_read_sample(indio_dev, chan->address, val); + mutex_unlock(&indio_dev->mlock); + return ret ? ret : IIO_VAL_INT; } - mutex_unlock(&indio_dev->mlock); - return ret; + return -EINVAL; } static const struct iio_chan_spec adis16080_channels[] = { From 3c80372dae17cb1a5a493c9ed02f7ca2a8d9ce53 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 32/40] staging:iio:adis16080: be16 cleanups The sample buffer contains big endian 16bit words. So use the be16 datatype for the buffer and use the proper helper functions for endianness conversion instead of openconding it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/adis16080_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index ddeae163982a..d033b6f486a6 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -39,7 +39,7 @@ struct adis16080_state { struct spi_device *us; struct mutex buf_lock; - u8 buf[2] ____cacheline_aligned; + __be16 buf ____cacheline_aligned; }; static int adis16080_read_sample(struct iio_dev *indio_dev, @@ -60,8 +60,7 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, }; mutex_lock(&st->buf_lock); - st->buf[0] = addr >> 8; - st->buf[1] = addr; + st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE); spi_message_init(&m); spi_message_add_tail(&t[0], &m); @@ -69,7 +68,7 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, ret = spi_sync(st->us, &m); if (ret == 0) - *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11); + *val = sign_extend32(be16_to_cpu(st->buf), 11); mutex_unlock(&st->buf_lock); return ret; From 61992d993beb5af8c64c617ec474439079aa726d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 33/40] staging:iio:adis16080: Remove unnecessary lock All sections in which the transfer buffer is accessed are already protected by the IIO device's mlock. So we do not need the extra mutex protecting the buffer. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/adis16080_core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index d033b6f486a6..76764ba16719 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -33,11 +33,9 @@ * struct adis16080_state - device instance specific data * @us: actual spi_device to write data * @buf: transmit or receive buffer - * @buf_lock: mutex to protect tx and rx **/ struct adis16080_state { struct spi_device *us; - struct mutex buf_lock; __be16 buf ____cacheline_aligned; }; @@ -59,7 +57,6 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, }, }; - mutex_lock(&st->buf_lock); st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE); spi_message_init(&m); @@ -69,7 +66,6 @@ static int adis16080_read_sample(struct iio_dev *indio_dev, ret = spi_sync(st->us, &m); if (ret == 0) *val = sign_extend32(be16_to_cpu(st->buf), 11); - mutex_unlock(&st->buf_lock); return ret; } @@ -144,7 +140,6 @@ static int adis16080_probe(struct spi_device *spi) /* Allocate the comms buffers */ st->us = spi; - mutex_init(&st->buf_lock); indio_dev->name = spi->dev.driver->name; indio_dev->channels = adis16080_channels; From 668cce24965a454f110c5835e0a2198a9aea55af Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 34/40] staging:iio:adis16080: Add scale and offset attributes Report scale and offset for the velocity, voltage and temperature channels. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/gyro/adis16080_core.c | 81 +++++++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 76764ba16719..098a0a18ce2d 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -29,13 +29,20 @@ #define ADIS16080_DIN_WRITE (1 << 15) +struct adis16080_chip_info { + int scale_val; + int scale_val2; +}; + /** * struct adis16080_state - device instance specific data * @us: actual spi_device to write data + * @info: chip specific parameters * @buf: transmit or receive buffer **/ struct adis16080_state { struct spi_device *us; + const struct adis16080_chip_info *info; __be16 buf ____cacheline_aligned; }; @@ -76,6 +83,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { + struct adis16080_state *st = iio_priv(indio_dev); int ret; switch (mask) { @@ -84,6 +92,40 @@ static int adis16080_read_raw(struct iio_dev *indio_dev, ret = adis16080_read_sample(indio_dev, chan->address, val); mutex_unlock(&indio_dev->mlock); return ret ? ret : IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = st->info->scale_val; + *val2 = st->info->scale_val2; + return IIO_VAL_FRACTIONAL; + case IIO_VOLTAGE: + /* VREF = 5V, 12 bits */ + *val = 5000; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_TEMP: + /* 85 C = 585, 25 C = 0 */ + *val = 85000 - 25000; + *val2 = 585; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_VOLTAGE: + /* 2.5 V = 0 */ + *val = 2048; + return IIO_VAL_INT; + case IIO_TEMP: + /* 85 C = 585, 25 C = 0 */ + *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25); + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + break; } return -EINVAL; @@ -94,25 +136,32 @@ static const struct iio_chan_spec adis16080_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = ADIS16080_DIN_GYRO, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, .address = ADIS16080_DIN_AIN1, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, .address = ADIS16080_DIN_AIN2, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, .address = ADIS16080_DIN_TEMP, } }; @@ -122,8 +171,27 @@ static const struct iio_info adis16080_info = { .driver_module = THIS_MODULE, }; +enum { + ID_ADIS16080, + ID_ADIS16100, +}; + +static const struct adis16080_chip_info adis16080_chip_info[] = { + [ID_ADIS16080] = { + /* 80 degree = 819, 819 rad = 46925 degree */ + .scale_val = 80, + .scale_val2 = 46925, + }, + [ID_ADIS16100] = { + /* 300 degree = 1230, 1230 rad = 70474 degree */ + .scale_val = 300, + .scale_val2 = 70474, + }, +}; + static int adis16080_probe(struct spi_device *spi) { + const struct spi_device_id *id = spi_get_device_id(spi); int ret; struct adis16080_state *st; struct iio_dev *indio_dev; @@ -140,6 +208,7 @@ static int adis16080_probe(struct spi_device *spi) /* Allocate the comms buffers */ st->us = spi; + st->info = &adis16080_chip_info[id->driver_data]; indio_dev->name = spi->dev.driver->name; indio_dev->channels = adis16080_channels; @@ -169,8 +238,8 @@ static int adis16080_remove(struct spi_device *spi) } static const struct spi_device_id adis16080_ids[] = { - { "adis16080", 0 }, - { "adis16100", 0 }, + { "adis16080", ID_ADIS16080 }, + { "adis16100", ID_ADIS16100 }, {}, }; MODULE_DEVICE_TABLE(spi, adis16080_ids); From a9fbbee8a2e90f88ff605ec72b388ec20b808ee4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Jan 2013 14:01:00 +0000 Subject: [PATCH 35/40] staging:iio:adis16080: Move out of staging The driver is rather simple and in a good shape. It follows the IIO ABI and the standard codechecker tools do not report any issues, so move it out of staging. While moving it also remove one outdated 'fixme' comment. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/Kconfig | 7 +++++++ drivers/iio/gyro/Makefile | 1 + .../iio/gyro/adis16080_core.c => iio/gyro/adis16080.c} | 1 - drivers/staging/iio/gyro/Kconfig | 7 ------- drivers/staging/iio/gyro/Makefile | 3 --- 5 files changed, 8 insertions(+), 11 deletions(-) rename drivers/{staging/iio/gyro/adis16080_core.c => iio/gyro/adis16080.c} (99%) diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 96b68f63a902..752ac8a3448b 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -3,6 +3,13 @@ # menu "Digital gyroscope sensors" +config ADIS16080 + tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw + Rate Gyroscope with SPI. + config ADIS16136 tristate "Analog devices ADIS16136 and similar gyroscopes driver" depends on SPI_MASTER diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile index 702a058907e3..9b090ee084d3 100644 --- a/drivers/iio/gyro/Makefile +++ b/drivers/iio/gyro/Makefile @@ -2,5 +2,6 @@ # Makefile for industrial I/O gyroscope sensor drivers # +obj-$(CONFIG_ADIS16080) += adis16080.o obj-$(CONFIG_ADIS16136) += adis16136.o obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/iio/gyro/adis16080.c similarity index 99% rename from drivers/staging/iio/gyro/adis16080_core.c rename to drivers/iio/gyro/adis16080.c index 098a0a18ce2d..1861287911f1 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/iio/gyro/adis16080.c @@ -228,7 +228,6 @@ static int adis16080_probe(struct spi_device *spi) return ret; } -/* fixme, confirm ordering in this function */ static int adis16080_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index a439e0512d5a..658b3673d056 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -10,13 +10,6 @@ config ADIS16060 Say yes here to build support for Analog Devices adis16060 wide bandwidth yaw rate gyroscope with SPI. -config ADIS16080 - tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw - Rate Gyroscope with SPI. - config ADIS16130 tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver" depends on SPI diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 79bef4ef7a54..ef3316171299 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -5,9 +5,6 @@ adis16060-y := adis16060_core.o obj-$(CONFIG_ADIS16060) += adis16060.o -adis16080-y := adis16080_core.o -obj-$(CONFIG_ADIS16080) += adis16080.o - adis16130-y := adis16130_core.o obj-$(CONFIG_ADIS16130) += adis16130.o From 5ade7633ac324098b31ae859f83cee73129d74d3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 12 Jan 2013 10:35:00 +0000 Subject: [PATCH 36/40] staging:iio:light:tsl2563 drop unnecessary brackets around constants. Not sure why these were ever there. Signed-off-by: Jonathan Cameron Acked-by: Peter Meerwald --- drivers/staging/iio/light/tsl2563.c | 66 ++++++++++++++--------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 1a9adc020f64..1ee0a6faf7c3 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -41,49 +41,49 @@ #include "tsl2563.h" /* Use this many bits for fraction part. */ -#define ADC_FRAC_BITS (14) +#define ADC_FRAC_BITS 14 /* Given number of 1/10000's in ADC_FRAC_BITS precision. */ #define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000)) /* Bits used for fraction in calibration coefficients.*/ -#define CALIB_FRAC_BITS (10) +#define CALIB_FRAC_BITS 10 /* 0.5 in CALIB_FRAC_BITS precision */ #define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1)) /* Make a fraction from a number n that was multiplied with b. */ #define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b)) /* Decimal 10^(digits in sysfs presentation) */ -#define CALIB_BASE_SYSFS (1000) - -#define TSL2563_CMD (0x80) -#define TSL2563_CLEARINT (0x40) - -#define TSL2563_REG_CTRL (0x00) -#define TSL2563_REG_TIMING (0x01) -#define TSL2563_REG_LOWLOW (0x02) /* data0 low threshold, 2 bytes */ -#define TSL2563_REG_LOWHIGH (0x03) -#define TSL2563_REG_HIGHLOW (0x04) /* data0 high threshold, 2 bytes */ -#define TSL2563_REG_HIGHHIGH (0x05) -#define TSL2563_REG_INT (0x06) -#define TSL2563_REG_ID (0x0a) -#define TSL2563_REG_DATA0LOW (0x0c) /* broadband sensor value, 2 bytes */ -#define TSL2563_REG_DATA0HIGH (0x0d) -#define TSL2563_REG_DATA1LOW (0x0e) /* infrared sensor value, 2 bytes */ -#define TSL2563_REG_DATA1HIGH (0x0f) - -#define TSL2563_CMD_POWER_ON (0x03) -#define TSL2563_CMD_POWER_OFF (0x00) -#define TSL2563_CTRL_POWER_MASK (0x03) - -#define TSL2563_TIMING_13MS (0x00) -#define TSL2563_TIMING_100MS (0x01) -#define TSL2563_TIMING_400MS (0x02) -#define TSL2563_TIMING_MASK (0x03) -#define TSL2563_TIMING_GAIN16 (0x10) -#define TSL2563_TIMING_GAIN1 (0x00) - -#define TSL2563_INT_DISBLED (0x00) -#define TSL2563_INT_LEVEL (0x10) +#define CALIB_BASE_SYSFS 1000 + +#define TSL2563_CMD 0x80 +#define TSL2563_CLEARINT 0x40 + +#define TSL2563_REG_CTRL 0x00 +#define TSL2563_REG_TIMING 0x01 +#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */ +#define TSL2563_REG_LOWHIGH 0x03 +#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */ +#define TSL2563_REG_HIGHHIGH 0x05 +#define TSL2563_REG_INT 0x06 +#define TSL2563_REG_ID 0x0a +#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */ +#define TSL2563_REG_DATA0HIGH 0x0d +#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */ +#define TSL2563_REG_DATA1HIGH 0x0f + +#define TSL2563_CMD_POWER_ON 0x03 +#define TSL2563_CMD_POWER_OFF 0x00 +#define TSL2563_CTRL_POWER_MASK 0x03 + +#define TSL2563_TIMING_13MS 0x00 +#define TSL2563_TIMING_100MS 0x01 +#define TSL2563_TIMING_400MS 0x02 +#define TSL2563_TIMING_MASK 0x03 +#define TSL2563_TIMING_GAIN16 0x10 +#define TSL2563_TIMING_GAIN1 0x00 + +#define TSL2563_INT_DISBLED 0x00 +#define TSL2563_INT_LEVEL 0x10 #define TSL2563_INT_PERSIST(n) ((n) & 0x0F) struct tsl2563_gainlevel_coeff { From a9e244f65df170ae6efba03bdb0a203626ae1cd3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 12 Jan 2013 10:35:00 +0000 Subject: [PATCH 37/40] staging:iio:light:tsl2563 clean comments up. Fix formatting of some comments and drop a few generic information free ones. Signed-off-by: Jonathan Cameron Acked-by: Peter Meerwald --- drivers/staging/iio/light/tsl2563.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 1ee0a6faf7c3..547203cfd5d5 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -190,8 +190,10 @@ static int tsl2563_configure(struct tsl2563_chip *chip) ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_LOWHIGH, (chip->low_thres >> 8) & 0xFF); -/* Interrupt register is automatically written anyway if it is relevant - so is not here */ +/* + * Interrupt register is automatically written anyway if it is relevant + * so is not here. + */ error_ret: return ret; } @@ -423,9 +425,7 @@ static const struct tsl2563_lux_coeff lux_table[] = { }, }; -/* - * Convert normalized, scaled ADC values to lux. - */ +/* Convert normalized, scaled ADC values to lux. */ static unsigned int adc_to_lux(u32 adc0, u32 adc1) { const struct tsl2563_lux_coeff *lp = lux_table; @@ -441,11 +441,6 @@ static unsigned int adc_to_lux(u32 adc0, u32 adc1) return (unsigned int) (lux >> ADC_FRAC_BITS); } -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - - /* Apply calibration coefficient to ADC count. */ static u32 calib_adc(u32 adc, u32 calib) { @@ -684,9 +679,6 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, return ret; } -/*--------------------------------------------------------------*/ -/* Probe, Attach, Remove */ -/*--------------------------------------------------------------*/ static struct i2c_driver tsl2563_i2c_driver; static const struct iio_info tsl2563_info_no_irq = { From a722dcca4da47a480a6042c0c0275695a597b77f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 12 Jan 2013 10:35:00 +0000 Subject: [PATCH 38/40] staging:iio:tsl2563 Simplify exit path on error in read_interrupt_config. A rather over complicated exit path given there is only one exit route and nothing much is done after it. Signed-off-by: Jonathan Cameron Acked-by: Peter Meerwald --- drivers/staging/iio/light/tsl2563.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 547203cfd5d5..1a3092a515ff 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -672,11 +672,9 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, TSL2563_CMD | TSL2563_REG_INT); mutex_unlock(&chip->lock); if (ret < 0) - goto error_ret; - ret = !!(ret & 0x30); -error_ret: + return ret; - return ret; + return !!(ret & 0x30); } static struct i2c_driver tsl2563_i2c_driver; From af0b8ee32c831e6e8fbfe0b311b9ac017d14b78d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 12 Jan 2013 10:35:00 +0000 Subject: [PATCH 39/40] staging:iio:tsl2563 drop pointless forward declaration Signed-off-by: Jonathan Cameron Acked-by: Peter Meerwald --- drivers/staging/iio/light/tsl2563.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 1a3092a515ff..b91d9bb8b083 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -677,8 +677,6 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, return !!(ret & 0x30); } -static struct i2c_driver tsl2563_i2c_driver; - static const struct iio_info tsl2563_info_no_irq = { .driver_module = THIS_MODULE, .read_raw = &tsl2563_read_raw, From 9c2251dd4b7feba14d35835c6835024840b1f76b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 12 Jan 2013 10:35:00 +0000 Subject: [PATCH 40/40] iio:light:tsl2563 move out of staging This driver is simple, uses the latest interfaces and contains few if any controversial elements. All of its interfaces have been in place for a long time now. Hence let's move it out of staging. Signed-off-by: Jonathan Cameron Acked-by: Peter Meerwald --- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- drivers/iio/light/Kconfig | 10 ++++++++++ drivers/iio/light/Makefile | 1 + drivers/{staging => }/iio/light/tsl2563.c | 4 ++-- drivers/staging/iio/light/Kconfig | 10 ---------- drivers/staging/iio/light/Makefile | 1 - .../light => include/linux/platform_data}/tsl2563.h | 1 - 7 files changed, 14 insertions(+), 15 deletions(-) rename drivers/{staging => }/iio/light/tsl2563.c (99%) rename {drivers/staging/iio/light => include/linux/platform_data}/tsl2563.h (99%) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index cf07e289b4ea..f3d075baebb6 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -42,7 +42,7 @@ #include #include -#include <../drivers/staging/iio/light/tsl2563.h> +#include #include #if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE) diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index dbf80abc834f..5ef1a396e0c9 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -32,6 +32,16 @@ config SENSORS_LM3533 changes. The ALS-control output values can be set per zone for the three current output channels. +config SENSORS_TSL2563 + tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" + depends on I2C + help + If you say yes here you get support for the Taos TSL2560, + TSL2561, TSL2562 and TSL2563 ambient light sensors. + + This driver can also be built as a module. If so, the module + will be called tsl2563. + config VCNL4000 tristate "VCNL4000 combined ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 21a8f0df1407..040d9c75f8e6 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_ADJD_S311) += adjd_s311.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o +obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c similarity index 99% rename from drivers/staging/iio/light/tsl2563.c rename to drivers/iio/light/tsl2563.c index b91d9bb8b083..fd8be69b7d05 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -1,5 +1,5 @@ /* - * drivers/i2c/chips/tsl2563.c + * drivers/iio/light/tsl2563.c * * Copyright (C) 2008 Nokia Corporation * @@ -38,7 +38,7 @@ #include #include #include -#include "tsl2563.h" +#include /* Use this many bits for fraction part. */ #define ADC_FRAC_BITS 14 diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 4bed30eac3ed..ca8d6e66c899 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -25,16 +25,6 @@ config SENSORS_ISL29028 Proximity value via iio. The ISL29028 provides the concurrent sensing of ambient light and proximity. -config SENSORS_TSL2563 - tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" - depends on I2C - help - If you say yes here you get support for the Taos TSL2560, - TSL2561, TSL2562 and TSL2563 ambient light sensors. - - This driver can also be built as a module. If so, the module - will be called tsl2563. - config TSL2583 tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters" depends on I2C diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 141af1eb164c..9960fdf7c15b 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,7 +2,6 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_TSL2583) += tsl2583.o diff --git a/drivers/staging/iio/light/tsl2563.h b/include/linux/platform_data/tsl2563.h similarity index 99% rename from drivers/staging/iio/light/tsl2563.h rename to include/linux/platform_data/tsl2563.h index b97368bd7fff..c90d7a09dda7 100644 --- a/drivers/staging/iio/light/tsl2563.h +++ b/include/linux/platform_data/tsl2563.h @@ -6,4 +6,3 @@ struct tsl2563_platform_data { }; #endif /* __LINUX_TSL2563_H */ -