Commit 985dbe77 authored by Michael Hennerich's avatar Michael Hennerich Committed by Greg Kroah-Hartman

staging: iio: adc: Enable driver support for ad799x AD converters

Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 and
ad7998 multichannel ADC.
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Acked-by: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e5558679
...@@ -26,3 +26,23 @@ config MAX1363_RING_BUFFER ...@@ -26,3 +26,23 @@ config MAX1363_RING_BUFFER
help help
Say yes here to include ring buffer support in the MAX1363 Say yes here to include ring buffer support in the MAX1363
ADC driver. ADC driver.
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
select IIO_TRIGGER if IIO_RING_BUFFER
select AD799X_RING_BUFFER
help
Say yes here to build support for Analog Devices:
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
i2c analog to digital convertors (ADC). Provides direct access
via sysfs.
config AD799X_RING_BUFFER
bool "Analog Devices AD799x: use ring buffer"
depends on AD799X
select IIO_RING_BUFFER
select IIO_SW_RING
help
Say yes here to include ring buffer support in the AD799X
ADC driver.
...@@ -6,3 +6,7 @@ max1363-y := max1363_core.o ...@@ -6,3 +6,7 @@ max1363-y := max1363_core.o
max1363-y += max1363_ring.o max1363-y += max1363_ring.o
obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MAX1363) += max1363.o
ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
obj-$(CONFIG_AD799X) += ad799x.o
\ No newline at end of file
/*
* Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
* Copyright (C) 2008-2010 Jonathan Cameron
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ad799x.h
*/
#ifndef _AD799X_H_
#define _AD799X_H_
#define AD799X_CHANNEL_SHIFT 4
/*
* AD7991, AD7995 and AD7999 defines
*/
#define AD7991_REF_SEL 0x08
#define AD7991_FLTR 0x04
#define AD7991_BIT_TRIAL_DELAY 0x02
#define AD7991_SAMPLE_DELAY 0x01
/*
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
*/
#define AD7998_FLTR 0x08
#define AD7998_ALERT_EN 0x04
#define AD7998_BUSY_ALERT 0x02
#define AD7998_BUSY_ALERT_POL 0x01
#define AD7998_CONV_RES_REG 0x0
#define AD7998_ALERT_STAT_REG 0x1
#define AD7998_CONF_REG 0x2
#define AD7998_CYCLE_TMR_REG 0x3
#define AD7998_DATALOW_CH1_REG 0x4
#define AD7998_DATAHIGH_CH1_REG 0x5
#define AD7998_HYST_CH1_REG 0x6
#define AD7998_DATALOW_CH2_REG 0x7
#define AD7998_DATAHIGH_CH2_REG 0x8
#define AD7998_HYST_CH2_REG 0x9
#define AD7998_DATALOW_CH3_REG 0xA
#define AD7998_DATAHIGH_CH3_REG 0xB
#define AD7998_HYST_CH3_REG 0xC
#define AD7998_DATALOW_CH4_REG 0xD
#define AD7998_DATAHIGH_CH4_REG 0xE
#define AD7998_HYST_CH4_REG 0xF
#define AD7998_CYC_MASK 0x7
#define AD7998_CYC_DIS 0x0
#define AD7998_CYC_TCONF_32 0x1
#define AD7998_CYC_TCONF_64 0x2
#define AD7998_CYC_TCONF_128 0x3
#define AD7998_CYC_TCONF_256 0x4
#define AD7998_CYC_TCONF_512 0x5
#define AD7998_CYC_TCONF_1024 0x6
#define AD7998_CYC_TCONF_2048 0x7
#define AD7998_ALERT_STAT_CLEAR 0xFF
/*
* AD7997 and AD7997 defines
*/
#define AD7997_8_READ_SINGLE 0x80
#define AD7997_8_READ_SEQUENCE 0x70
enum {
ad7991,
ad7995,
ad7999,
ad7992,
ad7993,
ad7994,
ad7997,
ad7998
};
struct ad799x_state;
/**
* struct ad799x_chip_info - chip specifc information
* @num_inputs: number of physical inputs on chip
* @bits: accuracy of the adc in bits
* @int_vref_mv: the internal reference voltage
* @monitor_mode: whether the chip supports monitor interrupts
* @default_config: device default configuration
* @dev_attrs: pointer to the device attribute group
* @scan_attrs: pointer to the scan element attribute group
* @event_attrs: pointer to the monitor event attribute group
* @ad799x_set_scan_mode: function pointer to the device specific mode function
*/
struct ad799x_chip_info {
u8 num_inputs;
u8 bits;
u16 int_vref_mv;
bool monitor_mode;
u16 default_config;
struct attribute_group *dev_attrs;
struct attribute_group *scan_attrs;
struct attribute_group *event_attrs;
int (*ad799x_set_scan_mode) (struct ad799x_state *st,
unsigned mask);
};
struct ad799x_state {
struct iio_dev *indio_dev;
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
struct work_struct poll_work;
struct work_struct work_thresh;
atomic_t protect_ring;
struct iio_trigger *trig;
struct regulator *reg;
s64 last_timestamp;
u16 int_vref_mv;
unsigned id;
char *name;
u16 config;
};
/*
* TODO: struct ad799x_platform_data needs to go into inlude/linux/iio
*/
struct ad799x_platform_data {
u16 vref_mv;
};
int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask);
#ifdef CONFIG_AD799X_RING_BUFFER
int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask);
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void ad799x_ring_cleanup(struct iio_dev *indio_dev);
#else /* CONFIG_AD799X_RING_BUFFER */
int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask)
{
return -EINVAL;
}
static inline int
ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return 0;
}
static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_AD799X_RING_BUFFER */
#endif /* _AD799X_H_ */
This diff is collapsed.
/*
* Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
* Copyright (C) 2008-2010 Jonathan Cameron
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ad799x_ring.c
*/
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/bitops.h>
#include "../iio.h"
#include "../ring_generic.h"
#include "../ring_sw.h"
#include "../trigger.h"
#include "../sysfs.h"
#include "ad799x.h"
int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask)
{
unsigned long numvals;
int count = 0, ret;
u16 *ring_data;
if (!(st->indio_dev->ring->scan_mask & mask)) {
ret = -EBUSY;
goto error_ret;
}
numvals = st->indio_dev->ring->scan_count;
ring_data = kmalloc(numvals*2, GFP_KERNEL);
if (ring_data == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = st->indio_dev->ring->access.read_last(st->indio_dev->ring,
(u8 *) ring_data);
if (ret)
goto error_free_ring_data;
/* Need a count of channels prior to this one */
mask >>= 1;
while (mask) {
if (mask & st->indio_dev->ring->scan_mask)
count++;
mask >>= 1;
}
ret = be16_to_cpu(ring_data[count]) & 0xFFF;
error_free_ring_data:
kfree(ring_data);
error_ret:
return ret;
}
/**
* ad799x_ring_preenable() setup the parameters of the ring before enabling
*
* The complex nature of the setting of the nuber of bytes per datum is due
* to this driver currently ensuring that the timestamp is stored at an 8
* byte boundary.
**/
static int ad799x_ring_preenable(struct iio_dev *indio_dev)
{
struct ad799x_state *st = indio_dev->dev_data;
size_t d_size;
unsigned long numvals;
/*
* Need to figure out the current mode based upon the requested
* scan mask in iio_dev
*/
if (st->id == ad7997 || st->id == ad7998)
ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask);
numvals = st->indio_dev->ring->scan_count;
if (indio_dev->ring->access.set_bytes_per_datum) {
d_size = numvals*2 + sizeof(s64);
if (d_size % 8)
d_size += 8 - (d_size % 8);
indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
d_size);
}
return 0;
}
/**
* ad799x_poll_func_th() th of trigger launched polling to ring buffer
*
* As sampling only occurs on i2c comms occuring, leave timestamping until
* then. Some triggers will generate their own time stamp. Currently
* there is no way of notifying them when no one cares.
**/
static void ad799x_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct ad799x_state *st = indio_dev->dev_data;
schedule_work(&st->poll_work);
return;
}
/**
* ad799x_poll_bh_to_ring() bh of trigger launched polling to ring buffer
* @work_s: the work struct through which this was scheduled
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
* I think the one copy of this at a time was to avoid problems if the
* trigger was set far too high and the reads then locked up the computer.
**/
static void ad799x_poll_bh_to_ring(struct work_struct *work_s)
{
struct ad799x_state *st = container_of(work_s, struct ad799x_state,
poll_work);
struct iio_dev *indio_dev = st->indio_dev;
struct iio_sw_ring_buffer *ring = iio_to_sw_ring(indio_dev->ring);
s64 time_ns;
__u8 *rxbuf;
int b_sent;
size_t d_size;
u8 cmd;
unsigned long numvals = st->indio_dev->ring->scan_count;
/* Ensure the timestamp is 8 byte aligned */
d_size = numvals*2 + sizeof(s64);
if (d_size % sizeof(s64))
d_size += sizeof(s64) - (d_size % sizeof(s64));
/* Ensure only one copy of this function running at a time */
if (atomic_inc_return(&st->protect_ring) > 1)
return;
/* Monitor mode prevents reading. Whilst not currently implemented
* might as well have this test in here in the meantime as it does
* no harm.
*/
if (numvals == 0)
return;
rxbuf = kmalloc(d_size, GFP_KERNEL);
if (rxbuf == NULL)
return;
switch (st->id) {
case ad7991:
case ad7995:
case ad7999:
cmd = st->config | (st->indio_dev->ring->scan_mask <<
AD799X_CHANNEL_SHIFT);
break;
case ad7992:
case ad7993:
case ad7994:
cmd = (st->indio_dev->ring->scan_mask <<
AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG;
break;
case ad7997:
case ad7998:
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
break;
default:
cmd = 0;
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
cmd, numvals*2, rxbuf);
if (b_sent < 0)
goto done;
time_ns = iio_get_time_ns();
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
indio_dev->ring->access.store_to(&ring->buf, rxbuf, time_ns);
done:
kfree(rxbuf);
atomic_dec(&st->protect_ring);
}
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
struct ad799x_state *st = indio_dev->dev_data;
int ret = 0;
indio_dev->ring = iio_sw_rb_allocate(indio_dev);
if (!indio_dev->ring) {
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&st->indio_dev->ring->access);
indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_deallocate_sw_rb;
}
/* Configure the polling function called on trigger interrupts */
indio_dev->pollfunc->poll_func_main = &ad799x_poll_func_th;
indio_dev->pollfunc->private_data = indio_dev;
/* Ring buffer functions - here trigger setup related */
indio_dev->ring->preenable = &ad799x_ring_preenable;
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring);
indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs;
/* Flag that polled ring buffering is possible */
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
error_deallocate_sw_rb:
iio_sw_rb_free(indio_dev->ring);
error_ret:
return ret;
}
void ad799x_ring_cleanup(struct iio_dev *indio_dev)
{
/* ensure that the trigger has been detached */
if (indio_dev->trig) {
iio_put_trigger(indio_dev->trig);
iio_trigger_dettach_poll_func(indio_dev->trig,
indio_dev->pollfunc);
}
kfree(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->ring);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment