Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

81
drivers/iio/Kconfig Normal file
View file

@ -0,0 +1,81 @@
#
# Industrial I/O subsystem configuration
#
menuconfig IIO
tristate "Industrial I/O support"
select ANON_INODES
help
The industrial I/O subsystem provides a unified framework for
drivers for many different types of embedded sensors using a
number of different physical interfaces (i2c, spi, etc).
if IIO
config IIO_BUFFER
bool "Enable buffer support within IIO"
help
Provide core support for various buffer based data
acquisition methods.
if IIO_BUFFER
config IIO_BUFFER_CB
boolean "IIO callback buffer used for push in-kernel interfaces"
help
Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
config IIO_KFIFO_BUF
select IIO_TRIGGER
tristate "Industrial I/O buffering based on kfifo"
help
A simple fifo based on kfifo. Note that this currently provides
no buffer events so it is up to userspace to work out how
often to read from the buffer.
config IIO_TRIGGERED_BUFFER
tristate
select IIO_TRIGGER
select IIO_KFIFO_BUF
help
Provides helper functions for setting up triggered buffers.
endif # IIO_BUFFER
config IIO_TRIGGER
boolean "Enable triggered sampling support"
help
Provides IIO core support for triggers. Currently these
are used to initialize capture of samples to push into
buffers. The triggers are effectively a 'capture
data now' interrupt.
config IIO_CONSUMERS_PER_TRIGGER
int "Maximum number of consumers per trigger"
depends on IIO_TRIGGER
default "2"
help
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
source "drivers/iio/humidity/Kconfig"
source "drivers/iio/imu/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/orientation/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/temperature/Kconfig"
endif # IIO

29
drivers/iio/Makefile Normal file
View file

@ -0,0 +1,29 @@
#
# Makefile for the industrial I/O core.
#
obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
obj-y += common/
obj-y += dac/
obj-y += gyro/
obj-y += frequency/
obj-y += humidity/
obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += orientation/
obj-y += pressure/
obj-y += proximity/
obj-y += temperature/
obj-y += trigger/

108
drivers/iio/accel/Kconfig Normal file
View file

@ -0,0 +1,108 @@
#
# Accelerometer drivers
#
# When adding new entries keep the list in alphabetical order
menu "Accelerometers"
config BMA180
tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Bosch BMA180 or
BMA250 triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma180.
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the following Bosch accelerometers:
BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
Currently this only supports the device via an i2c interface.
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing accelerometer part, which has
its own address and register map.
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
select HID_SENSOR_IIO_TRIGGER
tristate "HID Accelerometers 3D"
help
Say yes here to build support for the HID SENSOR
accelerometers 3D.
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
select IIO_ST_SENSORS_CORE
select IIO_ST_ACCEL_I2C_3AXIS if (I2C)
select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER)
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330.
This driver can also be built as a module. If so, these modules
will be created:
- st_accel (core functions for the driver [it is mandatory]);
- st_accel_i2c (necessary for the I2C devices [optional*]);
- st_accel_spi (necessary for the SPI devices [optional*]);
(*) one of these is necessary to do something.
config IIO_ST_ACCEL_I2C_3AXIS
tristate
depends on IIO_ST_ACCEL_3AXIS
depends on IIO_ST_SENSORS_I2C
config IIO_ST_ACCEL_SPI_3AXIS
tristate
depends on IIO_ST_ACCEL_3AXIS
depends on IIO_ST_SENSORS_SPI
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 MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the Freescale MMA8452Q 3-axis
accelerometer.
To compile this driver as a module, choose M here: the module
will be called mma8452.
config KXCJK1013
tristate "Kionix 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Kionix KXCJK-1013
triaxial acceleration sensor. This driver also supports KXCJ9-1008
and KXTJ2-1009.
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
endmenu

View file

@ -0,0 +1,18 @@
#
# Makefile for industrial I/O accelerometer drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_MMA8452) += mma8452.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
st_accel-y := st_accel_core.o
st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
obj-$(CONFIG_IIO_ST_ACCEL_I2C_3AXIS) += st_accel_i2c.o
obj-$(CONFIG_IIO_ST_ACCEL_SPI_3AXIS) += st_accel_spi.o

862
drivers/iio/accel/bma180.c Normal file
View file

@ -0,0 +1,862 @@
/*
* bma180.c - IIO driver for Bosch BMA180 triaxial acceleration sensor
*
* Copyright 2013 Oleksandr Kravchenko <x0199363@ti.com>
*
* Support for BMA250 (c) Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* SPI is not supported by driver
* BMA180: 7-bit I2C slave address 0x40 or 0x41
* BMA250: 7-bit I2C slave address 0x18 or 0x19
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define BMA180_DRV_NAME "bma180"
#define BMA180_IRQ_NAME "bma180_event"
enum {
BMA180,
BMA250,
};
struct bma180_data;
struct bma180_part_info {
const struct iio_chan_spec *channels;
unsigned num_channels;
const int *scale_table;
unsigned num_scales;
const int *bw_table;
unsigned num_bw;
u8 int_reset_reg, int_reset_mask;
u8 sleep_reg, sleep_mask;
u8 bw_reg, bw_mask;
u8 scale_reg, scale_mask;
u8 power_reg, power_mask, lowpower_val;
u8 int_enable_reg, int_enable_mask;
u8 softreset_reg;
int (*chip_config)(struct bma180_data *data);
void (*chip_disable)(struct bma180_data *data);
};
/* Register set */
#define BMA180_CHIP_ID 0x00 /* Need to distinguish BMA180 from other */
#define BMA180_ACC_X_LSB 0x02 /* First of 6 registers of accel data */
#define BMA180_TEMP 0x08
#define BMA180_CTRL_REG0 0x0d
#define BMA180_RESET 0x10
#define BMA180_BW_TCS 0x20
#define BMA180_CTRL_REG3 0x21
#define BMA180_TCO_Z 0x30
#define BMA180_OFFSET_LSB1 0x35
/* BMA180_CTRL_REG0 bits */
#define BMA180_DIS_WAKE_UP BIT(0) /* Disable wake up mode */
#define BMA180_SLEEP BIT(1) /* 1 - chip will sleep */
#define BMA180_EE_W BIT(4) /* Unlock writing to addr from 0x20 */
#define BMA180_RESET_INT BIT(6) /* Reset pending interrupts */
/* BMA180_CTRL_REG3 bits */
#define BMA180_NEW_DATA_INT BIT(1) /* Intr every new accel data is ready */
/* BMA180_OFFSET_LSB1 skipping mode bit */
#define BMA180_SMP_SKIP BIT(0)
/* Bit masks for registers bit fields */
#define BMA180_RANGE 0x0e /* Range of measured accel values */
#define BMA180_BW 0xf0 /* Accel bandwidth */
#define BMA180_MODE_CONFIG 0x03 /* Config operation modes */
/* We have to write this value in reset register to do soft reset */
#define BMA180_RESET_VAL 0xb6
#define BMA180_ID_REG_VAL 0x03
/* Chip power modes */
#define BMA180_LOW_POWER 0x03
#define BMA250_RANGE_REG 0x0f
#define BMA250_BW_REG 0x10
#define BMA250_POWER_REG 0x11
#define BMA250_RESET_REG 0x14
#define BMA250_INT_ENABLE_REG 0x17
#define BMA250_INT_MAP_REG 0x1a
#define BMA250_INT_RESET_REG 0x21
#define BMA250_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
#define BMA250_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
#define BMA250_SUSPEND_MASK BIT(7) /* chip will sleep */
#define BMA250_LOWPOWER_MASK BIT(6)
#define BMA250_DATA_INTEN_MASK BIT(4)
#define BMA250_INT1_DATA_MASK BIT(0)
#define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
struct bma180_data {
struct i2c_client *client;
struct iio_trigger *trig;
const struct bma180_part_info *part_info;
struct mutex mutex;
bool sleep_state;
int scale;
int bw;
bool pmode;
u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */
};
enum bma180_chan {
AXIS_X,
AXIS_Y,
AXIS_Z,
TEMP
};
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
0, 0, 306458 };
static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan)
{
int ret;
if (data->sleep_state)
return -EBUSY;
switch (chan) {
case TEMP:
ret = i2c_smbus_read_byte_data(data->client, BMA180_TEMP);
if (ret < 0)
dev_err(&data->client->dev, "failed to read temp register\n");
break;
default:
ret = i2c_smbus_read_word_data(data->client,
BMA180_ACC_X_LSB + chan * 2);
if (ret < 0)
dev_err(&data->client->dev,
"failed to read accel_%c register\n",
'x' + chan);
}
return ret;
}
static int bma180_set_bits(struct bma180_data *data, u8 reg, u8 mask, u8 val)
{
int ret = i2c_smbus_read_byte_data(data->client, reg);
u8 reg_val = (ret & ~mask) | (val << (ffs(mask) - 1));
if (ret < 0)
return ret;
return i2c_smbus_write_byte_data(data->client, reg, reg_val);
}
static int bma180_reset_intr(struct bma180_data *data)
{
int ret = bma180_set_bits(data, data->part_info->int_reset_reg,
data->part_info->int_reset_mask, 1);
if (ret)
dev_err(&data->client->dev, "failed to reset interrupt\n");
return ret;
}
static int bma180_set_new_data_intr_state(struct bma180_data *data, bool state)
{
int ret = bma180_set_bits(data, data->part_info->int_enable_reg,
data->part_info->int_enable_mask, state);
if (ret)
goto err;
ret = bma180_reset_intr(data);
if (ret)
goto err;
return 0;
err:
dev_err(&data->client->dev,
"failed to set new data interrupt state %d\n", state);
return ret;
}
static int bma180_set_sleep_state(struct bma180_data *data, bool state)
{
int ret = bma180_set_bits(data, data->part_info->sleep_reg,
data->part_info->sleep_mask, state);
if (ret) {
dev_err(&data->client->dev,
"failed to set sleep state %d\n", state);
return ret;
}
data->sleep_state = state;
return 0;
}
static int bma180_set_ee_writing_state(struct bma180_data *data, bool state)
{
int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_EE_W, state);
if (ret)
dev_err(&data->client->dev,
"failed to set ee writing state %d\n", state);
return ret;
}
static int bma180_set_bw(struct bma180_data *data, int val)
{
int ret, i;
if (data->sleep_state)
return -EBUSY;
for (i = 0; i < data->part_info->num_bw; ++i) {
if (data->part_info->bw_table[i] == val) {
ret = bma180_set_bits(data, data->part_info->bw_reg,
data->part_info->bw_mask, i);
if (ret) {
dev_err(&data->client->dev,
"failed to set bandwidth\n");
return ret;
}
data->bw = val;
return 0;
}
}
return -EINVAL;
}
static int bma180_set_scale(struct bma180_data *data, int val)
{
int ret, i;
if (data->sleep_state)
return -EBUSY;
for (i = 0; i < data->part_info->num_scales; ++i)
if (data->part_info->scale_table[i] == val) {
ret = bma180_set_bits(data, data->part_info->scale_reg,
data->part_info->scale_mask, i);
if (ret) {
dev_err(&data->client->dev,
"failed to set scale\n");
return ret;
}
data->scale = val;
return 0;
}
return -EINVAL;
}
static int bma180_set_pmode(struct bma180_data *data, bool mode)
{
u8 reg_val = mode ? data->part_info->lowpower_val : 0;
int ret = bma180_set_bits(data, data->part_info->power_reg,
data->part_info->power_mask, reg_val);
if (ret) {
dev_err(&data->client->dev, "failed to set power mode\n");
return ret;
}
data->pmode = mode;
return 0;
}
static int bma180_soft_reset(struct bma180_data *data)
{
int ret = i2c_smbus_write_byte_data(data->client,
data->part_info->softreset_reg, BMA180_RESET_VAL);
if (ret)
dev_err(&data->client->dev, "failed to reset the chip\n");
return ret;
}
static int bma180_chip_init(struct bma180_data *data)
{
/* Try to read chip_id register. It must return 0x03. */
int ret = i2c_smbus_read_byte_data(data->client, BMA180_CHIP_ID);
if (ret < 0)
return ret;
if (ret != BMA180_ID_REG_VAL)
return -ENODEV;
ret = bma180_soft_reset(data);
if (ret)
return ret;
/*
* No serial transaction should occur within minimum 10 us
* after soft_reset command
*/
msleep(20);
ret = bma180_set_new_data_intr_state(data, false);
if (ret)
return ret;
return bma180_set_pmode(data, false);
}
static int bma180_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
if (ret)
goto err;
ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1);
if (ret)
goto err;
ret = bma180_set_ee_writing_state(data, true);
if (ret)
goto err;
ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_SMP_SKIP, 1);
if (ret)
goto err;
ret = bma180_set_bw(data, 20); /* 20 Hz */
if (ret)
goto err;
ret = bma180_set_scale(data, 2452); /* 2 G */
if (ret)
goto err;
return 0;
err:
dev_err(&data->client->dev, "failed to config the chip\n");
return ret;
}
static int bma250_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
if (ret)
goto err;
ret = bma180_set_bw(data, 16); /* 16 Hz */
if (ret)
goto err;
ret = bma180_set_scale(data, 38344); /* 2 G */
if (ret)
goto err;
ret = bma180_set_bits(data, BMA250_INT_MAP_REG,
BMA250_INT1_DATA_MASK, 1);
if (ret)
goto err;
return 0;
err:
dev_err(&data->client->dev, "failed to config the chip\n");
return ret;
}
static void bma180_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
goto err;
if (bma180_set_ee_writing_state(data, false))
goto err;
if (bma180_set_sleep_state(data, true))
goto err;
return;
err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
static void bma250_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
goto err;
if (bma180_set_sleep_state(data, true))
goto err;
return;
err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
static ssize_t bma180_show_avail(char *buf, const int *vals, unsigned n,
bool micros)
{
size_t len = 0;
int i;
for (i = 0; i < n; i++) {
if (!vals[i])
continue;
len += scnprintf(buf + len, PAGE_SIZE - len,
micros ? "0.%06d " : "%d ", vals[i]);
}
buf[len - 1] = '\n';
return len;
}
static ssize_t bma180_show_filter_freq_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct bma180_data *data = iio_priv(dev_to_iio_dev(dev));
return bma180_show_avail(buf, data->part_info->bw_table,
data->part_info->num_bw, false);
}
static ssize_t bma180_show_scale_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct bma180_data *data = iio_priv(dev_to_iio_dev(dev));
return bma180_show_avail(buf, data->part_info->scale_table,
data->part_info->num_scales, true);
}
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
S_IRUGO, bma180_show_filter_freq_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_accel_scale_available,
S_IRUGO, bma180_show_scale_avail, NULL, 0);
static struct attribute *bma180_attributes[] = {
&iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.
dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group bma180_attrs_group = {
.attrs = bma180_attributes,
};
static int bma180_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
{
struct bma180_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&data->mutex);
return -EBUSY;
}
ret = bma180_get_data_reg(data, chan->scan_index);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
*val = sign_extend32(ret >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = data->bw;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ACCEL:
*val = 0;
*val2 = data->scale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
*val = 500;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 48; /* 0 LSB @ 24 degree C */
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int bma180_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct bma180_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (val)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma180_set_scale(data, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
if (val2)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma180_set_bw(data, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info bma180_info = {
.attrs = &bma180_attrs_group,
.read_raw = bma180_read_raw,
.write_raw = bma180_write_raw,
.driver_module = THIS_MODULE,
};
static const char * const bma180_power_modes[] = { "low_noise", "low_power" };
static int bma180_get_power_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma180_data *data = iio_priv(indio_dev);
return data->pmode;
}
static int bma180_set_power_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct bma180_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = bma180_set_pmode(data, mode);
mutex_unlock(&data->mutex);
return ret;
}
static const struct iio_enum bma180_power_mode_enum = {
.items = bma180_power_modes,
.num_items = ARRAY_SIZE(bma180_power_modes),
.get = bma180_get_power_mode,
.set = bma180_set_power_mode,
};
static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
{ },
};
#define BMA180_ACC_CHANNEL(_axis, _bits) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = AXIS_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = _bits, \
.storagebits = 16, \
.shift = 16 - _bits, \
}, \
.ext_info = bma180_ext_info, \
}
#define BMA180_TEMP_CHANNEL { \
.type = IIO_TEMP, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = TEMP, \
.scan_type = { \
.sign = 's', \
.realbits = 8, \
.storagebits = 16, \
}, \
}
static const struct iio_chan_spec bma180_channels[] = {
BMA180_ACC_CHANNEL(X, 14),
BMA180_ACC_CHANNEL(Y, 14),
BMA180_ACC_CHANNEL(Z, 14),
BMA180_TEMP_CHANNEL,
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec bma250_channels[] = {
BMA180_ACC_CHANNEL(X, 10),
BMA180_ACC_CHANNEL(Y, 10),
BMA180_ACC_CHANNEL(Z, 10),
BMA180_TEMP_CHANNEL,
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct bma180_part_info bma180_part_info[] = {
[BMA180] = {
bma180_channels, ARRAY_SIZE(bma180_channels),
bma180_scale_table, ARRAY_SIZE(bma180_scale_table),
bma180_bw_table, ARRAY_SIZE(bma180_bw_table),
BMA180_CTRL_REG0, BMA180_RESET_INT,
BMA180_CTRL_REG0, BMA180_SLEEP,
BMA180_BW_TCS, BMA180_BW,
BMA180_OFFSET_LSB1, BMA180_RANGE,
BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER,
BMA180_CTRL_REG3, BMA180_NEW_DATA_INT,
BMA180_RESET,
bma180_chip_config,
bma180_chip_disable,
},
[BMA250] = {
bma250_channels, ARRAY_SIZE(bma250_channels),
bma250_scale_table, ARRAY_SIZE(bma250_scale_table),
bma250_bw_table, ARRAY_SIZE(bma250_bw_table),
BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK,
BMA250_POWER_REG, BMA250_SUSPEND_MASK,
BMA250_BW_REG, BMA250_BW_MASK,
BMA250_RANGE_REG, BMA250_RANGE_MASK,
BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
BMA250_RESET_REG,
bma250_chip_config,
bma250_chip_disable,
},
};
static irqreturn_t bma180_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bma180_data *data = iio_priv(indio_dev);
int64_t time_ns = iio_get_time_ns();
int bit, ret, i = 0;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->buffer->scan_mask,
indio_dev->masklength) {
ret = bma180_get_data_reg(data, bit);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err;
}
((s16 *)data->buff)[i++] = ret;
}
mutex_unlock(&data->mutex);
iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int bma180_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bma180_data *data = iio_priv(indio_dev);
return bma180_set_new_data_intr_state(data, state);
}
static int bma180_trig_try_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bma180_data *data = iio_priv(indio_dev);
return bma180_reset_intr(data);
}
static const struct iio_trigger_ops bma180_trigger_ops = {
.set_trigger_state = bma180_data_rdy_trigger_set_state,
.try_reenable = bma180_trig_try_reen,
.owner = THIS_MODULE,
};
static int bma180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct bma180_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->part_info = &bma180_part_info[id->driver_data];
ret = data->part_info->chip_config(data);
if (ret < 0)
goto err_chip_disable;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->channels = data->part_info->channels;
indio_dev->num_channels = data->part_info->num_channels;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bma180_info;
if (client->irq > 0) {
data->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
indio_dev->id);
if (!data->trig) {
ret = -ENOMEM;
goto err_chip_disable;
}
ret = devm_request_irq(&client->dev, client->irq,
iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING,
"bma180_event", data->trig);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
goto err_trigger_free;
}
data->trig->dev.parent = &client->dev;
data->trig->ops = &bma180_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
indio_dev->trig = iio_trigger_get(data->trig);
ret = iio_trigger_register(data->trig);
if (ret)
goto err_trigger_free;
}
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bma180_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "unable to setup iio triggered buffer\n");
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
if (data->trig)
iio_trigger_unregister(data->trig);
err_trigger_free:
iio_trigger_free(data->trig);
err_chip_disable:
data->part_info->chip_disable(data);
return ret;
}
static int bma180_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct bma180_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (data->trig) {
iio_trigger_unregister(data->trig);
iio_trigger_free(data->trig);
}
mutex_lock(&data->mutex);
data->part_info->chip_disable(data);
mutex_unlock(&data->mutex);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int bma180_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct bma180_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = bma180_set_sleep_state(data, true);
mutex_unlock(&data->mutex);
return ret;
}
static int bma180_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct bma180_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = bma180_set_sleep_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
#define BMA180_PM_OPS (&bma180_pm_ops)
#else
#define BMA180_PM_OPS NULL
#endif
static struct i2c_device_id bma180_ids[] = {
{ "bma180", BMA180 },
{ "bma250", BMA250 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma180_ids);
static struct i2c_driver bma180_driver = {
.driver = {
.name = "bma180",
.owner = THIS_MODULE,
.pm = BMA180_PM_OPS,
},
.probe = bma180_probe,
.remove = bma180_remove,
.id_table = bma180_ids,
};
module_i2c_driver(bma180_driver);
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("Bosch BMA180/BMA250 triaxial acceleration sensor");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,430 @@
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum accel_3d_channel {
CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y,
CHANNEL_SCAN_INDEX_Z,
ACCEL_3D_CHANNEL_MAX,
};
struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
u32 accel_val[ACCEL_3D_CHANNEL_MAX];
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
};
static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ACCEL_X_AXIS,
HID_USAGE_SENSOR_ACCEL_Y_AXIS,
HID_USAGE_SENSOR_ACCEL_Z_AXIS
};
/* Channel definitions */
static const struct iio_chan_spec accel_3d_channels[] = {
{
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
/* Adjust channel real bits based on report descriptor */
static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
channels[channel].scan_type.realbits = size * 8;
/* Maximum size of a sample to capture is u32 */
channels[channel].scan_type.storagebits = sizeof(u32) * 8;
}
/* Channel read_raw handler */
static int accel_3d_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int report_id = -1;
u32 address;
int ret_type;
s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case 0:
poll_value = hid_sensor_read_poll_value(
&accel_state->common_attributes);
if (poll_value < 0)
return -EINVAL;
hid_sensor_power_state(&accel_state->common_attributes, true);
msleep_interruptible(poll_value * 2);
report_id = accel_state->accel[chan->scan_index].report_id;
address = accel_3d_addresses[chan->scan_index];
if (report_id >= 0)
*val = sensor_hub_input_attr_get_raw_value(
accel_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ACCEL_3D, address,
report_id);
else {
*val = 0;
hid_sensor_power_state(&accel_state->common_attributes,
false);
return -EINVAL;
}
hid_sensor_power_state(&accel_state->common_attributes, false);
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = accel_state->scale_pre_decml;
*val2 = accel_state->scale_post_decml;
ret_type = accel_state->scale_precision;
break;
case IIO_CHAN_INFO_OFFSET:
*val = accel_state->value_offset;
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SAMP_FREQ:
ret_type = hid_sensor_read_samp_freq_value(
&accel_state->common_attributes, val, val2);
break;
case IIO_CHAN_INFO_HYSTERESIS:
ret_type = hid_sensor_read_raw_hyst_value(
&accel_state->common_attributes, val, val2);
break;
default:
ret_type = -EINVAL;
break;
}
return ret_type;
}
/* Channel write_raw handler */
static int accel_3d_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int ret = 0;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
ret = hid_sensor_write_samp_freq_value(
&accel_state->common_attributes, val, val2);
break;
case IIO_CHAN_INFO_HYSTERESIS:
ret = hid_sensor_write_raw_hyst_value(
&accel_state->common_attributes, val, val2);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info accel_3d_info = {
.driver_module = THIS_MODULE,
.read_raw = &accel_3d_read_raw,
.write_raw = &accel_3d_write_raw,
};
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
int len)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, data);
}
/* Callback handler to send event after all samples are received and captured */
static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n");
if (atomic_read(&accel_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
accel_state->accel_val,
sizeof(accel_state->accel_val));
return 0;
}
/* Capture samples in local storage */
static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
size_t raw_len, char *raw_data,
void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int offset;
int ret = -EINVAL;
switch (usage_id) {
case HID_USAGE_SENSOR_ACCEL_X_AXIS:
case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
ret = 0;
break;
default:
break;
}
return ret;
}
/* Parse report which is specific to an usage id*/
static int accel_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
unsigned usage_id,
struct accel_3d_state *st)
{
int ret;
int i;
for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
&st->accel[CHANNEL_SCAN_INDEX_X + i]);
if (ret < 0)
break;
accel_3d_adjust_channel_bit_mask(channels,
CHANNEL_SCAN_INDEX_X + i,
st->accel[CHANNEL_SCAN_INDEX_X + i].size);
}
dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
st->accel[0].index,
st->accel[0].report_id,
st->accel[1].index, st->accel[1].report_id,
st->accel[2].index, st->accel[2].report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_ACCEL_3D,
&st->accel[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
/* Set Sensitivity field ids, when there is no individual modifier */
if (st->common_attributes.sensitivity.index < 0) {
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
HID_USAGE_SENSOR_DATA_ACCELERATION,
&st->common_attributes.sensitivity);
dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
st->common_attributes.sensitivity.index,
st->common_attributes.sensitivity.report_id);
}
return ret;
}
/* Function to initialize the processing for usage id */
static int hid_accel_3d_probe(struct platform_device *pdev)
{
int ret = 0;
static const char *name = "accel_3d";
struct iio_dev *indio_dev;
struct accel_3d_state *accel_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct accel_3d_state));
if (indio_dev == NULL)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
accel_state = iio_priv(indio_dev);
accel_state->common_attributes.hsdev = hsdev;
accel_state->common_attributes.pdev = pdev;
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_ACCEL_3D,
&accel_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
GFP_KERNEL);
if (!channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = accel_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_ACCEL_3D, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &accel_3d_info;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&accel_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&accel_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "device register failed\n");
goto error_remove_trigger;
}
accel_state->callbacks.send_event = accel_3d_proc_event;
accel_state->callbacks.capture_sample = accel_3d_capture_sample;
accel_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
&accel_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
goto error_iio_unreg;
}
return ret;
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&accel_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
}
/* Function to deinitialize the processing for usage id */
static int hid_accel_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&accel_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
return 0;
}
static struct platform_device_id hid_accel_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200073",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
static struct platform_driver hid_accel_3d_platform_driver = {
.id_table = hid_accel_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
},
.probe = hid_accel_3d_probe,
.remove = hid_accel_3d_remove,
};
module_platform_driver(hid_accel_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Accel 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load diff

276
drivers/iio/accel/kxsd9.c Normal file
View file

@ -0,0 +1,276 @@
/*
* kxsd9.c simple support for the Kionix KXSD9 3D
* accelerometer.
*
* Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org>
*
* 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.
*
* The i2c interface is very similar, so shouldn't be a problem once
* I have a suitable wire made up.
*
* TODO: Support the motion detector
* Uses register address incrementing so could have a
* heavily optimized ring buffer access function.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define KXSD9_REG_X 0x00
#define KXSD9_REG_Y 0x02
#define KXSD9_REG_Z 0x04
#define KXSD9_REG_AUX 0x06
#define KXSD9_REG_RESET 0x0a
#define KXSD9_REG_CTRL_C 0x0c
#define KXSD9_FS_MASK 0x03
#define KXSD9_REG_CTRL_B 0x0d
#define KXSD9_REG_CTRL_A 0x0e
#define KXSD9_READ(a) (0x80 | (a))
#define KXSD9_WRITE(a) (a)
#define KXSD9_STATE_RX_SIZE 2
#define KXSD9_STATE_TX_SIZE 2
/**
* struct kxsd9_state - device related storage
* @buf_lock: protect the rx and tx buffers.
* @us: spi device
* @rx: single rx buffer storage
* @tx: single tx buffer storage
**/
struct kxsd9_state {
struct mutex buf_lock;
struct spi_device *us;
u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned;
u8 tx[KXSD9_STATE_TX_SIZE];
};
#define KXSD9_SCALE_2G "0.011978"
#define KXSD9_SCALE_4G "0.023927"
#define KXSD9_SCALE_6G "0.035934"
#define KXSD9_SCALE_8G "0.047853"
/* reverse order */
static const int kxsd9_micro_scales[4] = { 47853, 35934, 23927, 11978 };
static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
{
int ret, i;
struct kxsd9_state *st = iio_priv(indio_dev);
bool foundit = false;
for (i = 0; i < 4; i++)
if (micro == kxsd9_micro_scales[i]) {
foundit = true;
break;
}
if (!foundit)
return -EINVAL;
mutex_lock(&st->buf_lock);
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
if (ret)
goto error_ret;
st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
st->tx[1] = (ret & ~KXSD9_FS_MASK) | i;
ret = spi_write(st->us, st->tx, 2);
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
{
int ret;
struct kxsd9_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.bits_per_word = 8,
.len = 1,
.delay_usecs = 200,
.tx_buf = st->tx,
}, {
.bits_per_word = 8,
.len = 2,
.rx_buf = st->rx,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = KXSD9_READ(address);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (!ret)
ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
mutex_unlock(&st->buf_lock);
return ret;
}
static IIO_CONST_ATTR(accel_scale_available,
KXSD9_SCALE_2G " "
KXSD9_SCALE_4G " "
KXSD9_SCALE_6G " "
KXSD9_SCALE_8G);
static struct attribute *kxsd9_attributes[] = {
&iio_const_attr_accel_scale_available.dev_attr.attr,
NULL,
};
static int kxsd9_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
int ret = -EINVAL;
if (mask == IIO_CHAN_INFO_SCALE) {
/* Check no integer component */
if (val)
return -EINVAL;
ret = kxsd9_write_scale(indio_dev, val2);
}
return ret;
}
static int kxsd9_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = -EINVAL;
struct kxsd9_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = kxsd9_read(indio_dev, chan->address);
if (ret < 0)
goto error_ret;
*val = ret;
break;
case IIO_CHAN_INFO_SCALE:
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
if (ret)
goto error_ret;
*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
ret = IIO_VAL_INT_PLUS_MICRO;
break;
}
error_ret:
return ret;
};
#define KXSD9_ACCEL_CHAN(axis) \
{ \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = KXSD9_REG_##axis, \
}
static const struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.indexed = 1,
.address = KXSD9_REG_AUX,
}
};
static const struct attribute_group kxsd9_attribute_group = {
.attrs = kxsd9_attributes,
};
static int kxsd9_power_up(struct kxsd9_state *st)
{
int ret;
st->tx[0] = 0x0d;
st->tx[1] = 0x40;
ret = spi_write(st->us, st->tx, 2);
if (ret)
return ret;
st->tx[0] = 0x0c;
st->tx[1] = 0x9b;
return spi_write(st->us, st->tx, 2);
};
static const struct iio_info kxsd9_info = {
.read_raw = &kxsd9_read_raw,
.write_raw = &kxsd9_write_raw,
.attrs = &kxsd9_attribute_group,
.driver_module = THIS_MODULE,
};
static int kxsd9_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct kxsd9_state *st;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->channels = kxsd9_channels;
indio_dev->num_channels = ARRAY_SIZE(kxsd9_channels);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &kxsd9_info;
indio_dev->modes = INDIO_DIRECT_MODE;
spi->mode = SPI_MODE_0;
spi_setup(spi);
kxsd9_power_up(st);
return iio_device_register(indio_dev);
}
static int kxsd9_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
return 0;
}
static const struct spi_device_id kxsd9_id[] = {
{"kxsd9", 0},
{ },
};
MODULE_DEVICE_TABLE(spi, kxsd9_id);
static struct spi_driver kxsd9_driver = {
.driver = {
.name = "kxsd9",
.owner = THIS_MODULE,
},
.probe = kxsd9_probe,
.remove = kxsd9_remove,
.id_table = kxsd9_id,
};
module_spi_driver(kxsd9_driver);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
MODULE_LICENSE("GPL v2");

451
drivers/iio/accel/mma8452.c Normal file
View file

@ -0,0 +1,451 @@
/*
* mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
*
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
*
* TODO: interrupt, thresholding, orientation / freefall events, autosleep
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/delay.h>
#define MMA8452_STATUS 0x00
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
#define MMA8452_OUT_Y 0x03
#define MMA8452_OUT_Z 0x05
#define MMA8452_WHO_AM_I 0x0d
#define MMA8452_DATA_CFG 0x0e
#define MMA8452_OFF_X 0x2f
#define MMA8452_OFF_Y 0x30
#define MMA8452_OFF_Z 0x31
#define MMA8452_CTRL_REG1 0x2a
#define MMA8452_CTRL_REG2 0x2b
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
#define MMA8452_CTRL_DR_SHIFT 3
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
#define MMA8452_CTRL_ACTIVE BIT(0)
#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
#define MMA8452_DATA_CFG_FS_2G 0
#define MMA8452_DATA_CFG_FS_4G 1
#define MMA8452_DATA_CFG_FS_8G 2
#define MMA8452_DEVICE_ID 0x2a
struct mma8452_data {
struct i2c_client *client;
struct mutex lock;
u8 ctrl_reg1;
u8 data_cfg;
};
static int mma8452_drdy(struct mma8452_data *data)
{
int tries = 150;
while (tries-- > 0) {
int ret = i2c_smbus_read_byte_data(data->client,
MMA8452_STATUS);
if (ret < 0)
return ret;
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
return 0;
msleep(20);
}
dev_err(&data->client->dev, "data not ready\n");
return -EIO;
}
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
{
int ret = mma8452_drdy(data);
if (ret < 0)
return ret;
return i2c_smbus_read_i2c_block_data(data->client,
MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
}
static ssize_t mma8452_show_int_plus_micros(char *buf,
const int (*vals)[2], int n)
{
size_t len = 0;
while (n-- > 0)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%d.%06d ", vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
return len;
}
static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
int val, int val2)
{
while (n-- > 0)
if (val == vals[n][0] && val2 == vals[n][1])
return n;
return -EINVAL;
}
static const int mma8452_samp_freq[8][2] = {
{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
{6, 250000}, {1, 560000}
};
/*
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor is given by:
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
*/
static const int mma8452_scales[3][2] = {
{0, 9577}, {0, 19154}, {0, 38307}
};
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
ARRAY_SIZE(mma8452_samp_freq));
}
static ssize_t mma8452_show_scale_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_scales,
ARRAY_SIZE(mma8452_scales));
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
mma8452_show_scale_avail, NULL, 0);
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
ARRAY_SIZE(mma8452_samp_freq), val, val2);
}
static int mma8452_get_scale_index(struct mma8452_data *data,
int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_scales,
ARRAY_SIZE(mma8452_scales), val, val2);
}
static int mma8452_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mma8452_data *data = iio_priv(indio_dev);
__be16 buffer[3];
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
mutex_lock(&data->lock);
ret = mma8452_read(data, buffer);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = sign_extend32(
be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
*val = mma8452_scales[i][0];
*val2 = mma8452_scales[i][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
i = (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
MMA8452_CTRL_DR_SHIFT;
*val = mma8452_samp_freq[i][0];
*val2 = mma8452_samp_freq[i][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
chan->scan_index);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 7);
return IIO_VAL_INT;
}
return -EINVAL;
}
static int mma8452_standby(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
}
static int mma8452_active(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
}
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
{
int ret;
mutex_lock(&data->lock);
/* config can only be changed when in standby */
ret = mma8452_standby(data);
if (ret < 0)
goto fail;
ret = i2c_smbus_write_byte_data(data->client, reg, val);
if (ret < 0)
goto fail;
ret = mma8452_active(data);
if (ret < 0)
goto fail;
ret = 0;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int mma8452_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mma8452_data *data = iio_priv(indio_dev);
int i;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_samp_freq_index(data, val, val2);
if (i < 0)
return -EINVAL;
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
return mma8452_change_config(data, MMA8452_CTRL_REG1,
data->ctrl_reg1);
case IIO_CHAN_INFO_SCALE:
i = mma8452_get_scale_index(data, val, val2);
if (i < 0)
return -EINVAL;
data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
data->data_cfg |= i;
return mma8452_change_config(data, MMA8452_DATA_CFG,
data->data_cfg);
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -128 || val > 127)
return -EINVAL;
return mma8452_change_config(data, MMA8452_OFF_X +
chan->scan_index, val);
default:
return -EINVAL;
}
}
static irqreturn_t mma8452_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mma8452_data *data = iio_priv(indio_dev);
u8 buffer[16]; /* 3 16-bit channels + padding + ts */
int ret;
ret = mma8452_read(data, (__be16 *) buffer);
if (ret < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
#define MMA8452_CHANNEL(axis, idx) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
.storagebits = 16, \
.shift = 4, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec mma8452_channels[] = {
MMA8452_CHANNEL(X, 0),
MMA8452_CHANNEL(Y, 1),
MMA8452_CHANNEL(Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static struct attribute *mma8452_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group mma8452_group = {
.attrs = mma8452_attributes,
};
static const struct iio_info mma8452_info = {
.attrs = &mma8452_group,
.read_raw = &mma8452_read_raw,
.write_raw = &mma8452_write_raw,
.driver_module = THIS_MODULE,
};
static const unsigned long mma8452_scan_masks[] = {0x7, 0};
static int mma8452_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
if (ret < 0)
return ret;
if (ret != MMA8452_DEVICE_ID)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->client = client;
mutex_init(&data->lock);
i2c_set_clientdata(client, indio_dev);
indio_dev->info = &mma8452_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mma8452_channels;
indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
indio_dev->available_scan_masks = mma8452_scan_masks;
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
if (ret < 0)
return ret;
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
data->data_cfg);
if (ret < 0)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mma8452_trigger_handler, NULL);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0)
goto buffer_cleanup;
return 0;
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int mma8452_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mma8452_suspend(struct device *dev)
{
return mma8452_standby(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
}
static int mma8452_resume(struct device *dev)
{
return mma8452_active(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
}
static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
#define MMA8452_PM_OPS (&mma8452_pm_ops)
#else
#define MMA8452_PM_OPS NULL
#endif
static const struct i2c_device_id mma8452_id[] = {
{ "mma8452", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
static const struct of_device_id mma8452_dt_ids[] = {
{ .compatible = "fsl,mma8452" },
{ }
};
static struct i2c_driver mma8452_driver = {
.driver = {
.name = "mma8452",
.of_match_table = of_match_ptr(mma8452_dt_ids),
.pm = MMA8452_PM_OPS,
},
.probe = mma8452_probe,
.remove = mma8452_remove,
.id_table = mma8452_id,
};
module_i2c_driver(mma8452_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,56 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
* v. 1.0.0
* Licensed under the GPL-2.
*/
#ifndef ST_ACCEL_H
#define ST_ACCEL_H
#include <linux/types.h>
#include <linux/iio/common/st_sensors.h>
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
#define LIS3DH_ACCEL_DEV_NAME "lis3dh"
#define LSM330D_ACCEL_DEV_NAME "lsm330d_accel"
#define LSM330DL_ACCEL_DEV_NAME "lsm330dl_accel"
#define LSM330DLC_ACCEL_DEV_NAME "lsm330dlc_accel"
#define LIS331DLH_ACCEL_DEV_NAME "lis331dlh"
#define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel"
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
/**
* struct st_sensors_platform_data - default accel platform data
* @drdy_int_pin: default accel DRDY is available on INT1 pin.
*/
static const struct st_sensors_platform_data default_accel_pdata = {
.drdy_int_pin = 1,
};
int st_accel_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata);
void st_accel_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
int st_accel_allocate_ring(struct iio_dev *indio_dev);
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
int st_accel_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
static inline int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev)
{
}
#define ST_ACCEL_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
#endif /* ST_ACCEL_H */

View file

@ -0,0 +1,105 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
#include "st_accel.h"
int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state);
}
static int st_accel_buffer_preenable(struct iio_dev *indio_dev)
{
return st_sensors_set_enable(indio_dev, true);
}
static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (adata->buffer_data == NULL) {
err = -ENOMEM;
goto allocate_memory_error;
}
err = st_sensors_set_axis_enable(indio_dev,
(u8)indio_dev->active_scan_mask[0]);
if (err < 0)
goto st_accel_buffer_postenable_error;
err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_accel_buffer_postenable_error;
return err;
st_accel_buffer_postenable_error:
kfree(adata->buffer_data);
allocate_memory_error:
return err;
}
static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
err = iio_triggered_buffer_predisable(indio_dev);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_enable(indio_dev, false);
st_accel_buffer_predisable_error:
kfree(adata->buffer_data);
return err;
}
static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
.preenable = &st_accel_buffer_preenable,
.postenable = &st_accel_buffer_postenable,
.predisable = &st_accel_buffer_predisable,
};
int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
}
void st_accel_deallocate_ring(struct iio_dev *indio_dev)
{
iio_triggered_buffer_cleanup(indio_dev);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers buffer");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,540 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/common/st_sensors.h>
#include "st_accel.h"
#define ST_ACCEL_NUMBER_DATA_CHANNELS 3
/* DEFAULT VALUE FOR SENSORS */
#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
/* FULLSCALE */
#define ST_ACCEL_FS_AVL_2G 2
#define ST_ACCEL_FS_AVL_4G 4
#define ST_ACCEL_FS_AVL_6G 6
#define ST_ACCEL_FS_AVL_8G 8
#define ST_ACCEL_FS_AVL_16G 16
/* CUSTOM VALUES FOR SENSOR 1 */
#define ST_ACCEL_1_WAI_EXP 0x33
#define ST_ACCEL_1_ODR_ADDR 0x20
#define ST_ACCEL_1_ODR_MASK 0xf0
#define ST_ACCEL_1_ODR_AVL_1HZ_VAL 0x01
#define ST_ACCEL_1_ODR_AVL_10HZ_VAL 0x02
#define ST_ACCEL_1_ODR_AVL_25HZ_VAL 0x03
#define ST_ACCEL_1_ODR_AVL_50HZ_VAL 0x04
#define ST_ACCEL_1_ODR_AVL_100HZ_VAL 0x05
#define ST_ACCEL_1_ODR_AVL_200HZ_VAL 0x06
#define ST_ACCEL_1_ODR_AVL_400HZ_VAL 0x07
#define ST_ACCEL_1_ODR_AVL_1600HZ_VAL 0x08
#define ST_ACCEL_1_FS_ADDR 0x23
#define ST_ACCEL_1_FS_MASK 0x30
#define ST_ACCEL_1_FS_AVL_2_VAL 0x00
#define ST_ACCEL_1_FS_AVL_4_VAL 0x01
#define ST_ACCEL_1_FS_AVL_8_VAL 0x02
#define ST_ACCEL_1_FS_AVL_16_VAL 0x03
#define ST_ACCEL_1_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
#define ST_ACCEL_1_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
#define ST_ACCEL_1_FS_AVL_8_GAIN IIO_G_TO_M_S_2(4000)
#define ST_ACCEL_1_FS_AVL_16_GAIN IIO_G_TO_M_S_2(12000)
#define ST_ACCEL_1_BDU_ADDR 0x23
#define ST_ACCEL_1_BDU_MASK 0x80
#define ST_ACCEL_1_DRDY_IRQ_ADDR 0x22
#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK 0x10
#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK 0x08
#define ST_ACCEL_1_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 2 */
#define ST_ACCEL_2_WAI_EXP 0x32
#define ST_ACCEL_2_ODR_ADDR 0x20
#define ST_ACCEL_2_ODR_MASK 0x18
#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
#define ST_ACCEL_2_PW_ADDR 0x20
#define ST_ACCEL_2_PW_MASK 0xe0
#define ST_ACCEL_2_FS_ADDR 0x23
#define ST_ACCEL_2_FS_MASK 0x30
#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
#define ST_ACCEL_2_BDU_ADDR 0x23
#define ST_ACCEL_2_BDU_MASK 0x80
#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK 0x02
#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10
#define ST_ACCEL_2_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 3 */
#define ST_ACCEL_3_WAI_EXP 0x40
#define ST_ACCEL_3_ODR_ADDR 0x20
#define ST_ACCEL_3_ODR_MASK 0xf0
#define ST_ACCEL_3_ODR_AVL_3HZ_VAL 0x01
#define ST_ACCEL_3_ODR_AVL_6HZ_VAL 0x02
#define ST_ACCEL_3_ODR_AVL_12HZ_VAL 0x03
#define ST_ACCEL_3_ODR_AVL_25HZ_VAL 0x04
#define ST_ACCEL_3_ODR_AVL_50HZ_VAL 0x05
#define ST_ACCEL_3_ODR_AVL_100HZ_VAL 0x06
#define ST_ACCEL_3_ODR_AVL_200HZ_VAL 0x07
#define ST_ACCEL_3_ODR_AVL_400HZ_VAL 0x08
#define ST_ACCEL_3_ODR_AVL_800HZ_VAL 0x09
#define ST_ACCEL_3_ODR_AVL_1600HZ_VAL 0x0a
#define ST_ACCEL_3_FS_ADDR 0x24
#define ST_ACCEL_3_FS_MASK 0x38
#define ST_ACCEL_3_FS_AVL_2_VAL 0X00
#define ST_ACCEL_3_FS_AVL_4_VAL 0X01
#define ST_ACCEL_3_FS_AVL_6_VAL 0x02
#define ST_ACCEL_3_FS_AVL_8_VAL 0x03
#define ST_ACCEL_3_FS_AVL_16_VAL 0x04
#define ST_ACCEL_3_FS_AVL_2_GAIN IIO_G_TO_M_S_2(61)
#define ST_ACCEL_3_FS_AVL_4_GAIN IIO_G_TO_M_S_2(122)
#define ST_ACCEL_3_FS_AVL_6_GAIN IIO_G_TO_M_S_2(183)
#define ST_ACCEL_3_FS_AVL_8_GAIN IIO_G_TO_M_S_2(244)
#define ST_ACCEL_3_FS_AVL_16_GAIN IIO_G_TO_M_S_2(732)
#define ST_ACCEL_3_BDU_ADDR 0x20
#define ST_ACCEL_3_BDU_MASK 0x08
#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23
#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK 0x80
#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK 0x00
#define ST_ACCEL_3_IG1_EN_ADDR 0x23
#define ST_ACCEL_3_IG1_EN_MASK 0x08
#define ST_ACCEL_3_MULTIREAD_BIT false
static const struct iio_chan_spec st_accel_12bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16,
ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16,
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16,
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensors st_accel_sensors[] = {
{
.wai = ST_ACCEL_1_WAI_EXP,
.sensors_supported = {
[0] = LIS3DH_ACCEL_DEV_NAME,
[1] = LSM303DLHC_ACCEL_DEV_NAME,
[2] = LSM330D_ACCEL_DEV_NAME,
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = ST_ACCEL_1_ODR_ADDR,
.mask = ST_ACCEL_1_ODR_MASK,
.odr_avl = {
{ 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, },
{ 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, },
{ 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, },
{ 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, },
{ 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, },
{ 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, },
{ 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, },
{ 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_1_ODR_ADDR,
.mask = ST_ACCEL_1_ODR_MASK,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_1_FS_ADDR,
.mask = ST_ACCEL_1_FS_MASK,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = ST_ACCEL_1_FS_AVL_2_VAL,
.gain = ST_ACCEL_1_FS_AVL_2_GAIN,
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = ST_ACCEL_1_FS_AVL_4_VAL,
.gain = ST_ACCEL_1_FS_AVL_4_GAIN,
},
[2] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = ST_ACCEL_1_FS_AVL_8_VAL,
.gain = ST_ACCEL_1_FS_AVL_8_GAIN,
},
[3] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = ST_ACCEL_1_FS_AVL_16_VAL,
.gain = ST_ACCEL_1_FS_AVL_16_GAIN,
},
},
},
.bdu = {
.addr = ST_ACCEL_1_BDU_ADDR,
.mask = ST_ACCEL_1_BDU_MASK,
},
.drdy_irq = {
.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
.bootime = 2,
},
{
.wai = ST_ACCEL_2_WAI_EXP,
.sensors_supported = {
[0] = LIS331DLH_ACCEL_DEV_NAME,
[1] = LSM303DL_ACCEL_DEV_NAME,
[2] = LSM303DLH_ACCEL_DEV_NAME,
[3] = LSM303DLM_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = ST_ACCEL_2_ODR_ADDR,
.mask = ST_ACCEL_2_ODR_MASK,
.odr_avl = {
{ 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
{ 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
{ 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
{ 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_2_PW_ADDR,
.mask = ST_ACCEL_2_PW_MASK,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_2_FS_ADDR,
.mask = ST_ACCEL_2_FS_MASK,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = ST_ACCEL_2_FS_AVL_2_VAL,
.gain = ST_ACCEL_2_FS_AVL_2_GAIN,
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = ST_ACCEL_2_FS_AVL_4_VAL,
.gain = ST_ACCEL_2_FS_AVL_4_GAIN,
},
[2] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = ST_ACCEL_2_FS_AVL_8_VAL,
.gain = ST_ACCEL_2_FS_AVL_8_GAIN,
},
},
},
.bdu = {
.addr = ST_ACCEL_2_BDU_ADDR,
.mask = ST_ACCEL_2_BDU_MASK,
},
.drdy_irq = {
.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
.bootime = 2,
},
{
.wai = ST_ACCEL_3_WAI_EXP,
.sensors_supported = {
[0] = LSM330_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
.addr = ST_ACCEL_3_ODR_ADDR,
.mask = ST_ACCEL_3_ODR_MASK,
.odr_avl = {
{ 3, ST_ACCEL_3_ODR_AVL_3HZ_VAL },
{ 6, ST_ACCEL_3_ODR_AVL_6HZ_VAL, },
{ 12, ST_ACCEL_3_ODR_AVL_12HZ_VAL, },
{ 25, ST_ACCEL_3_ODR_AVL_25HZ_VAL, },
{ 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, },
{ 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, },
{ 200, ST_ACCEL_3_ODR_AVL_200HZ_VAL, },
{ 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, },
{ 800, ST_ACCEL_3_ODR_AVL_800HZ_VAL, },
{ 1600, ST_ACCEL_3_ODR_AVL_1600HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_3_ODR_ADDR,
.mask = ST_ACCEL_3_ODR_MASK,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_3_FS_ADDR,
.mask = ST_ACCEL_3_FS_MASK,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = ST_ACCEL_3_FS_AVL_2_VAL,
.gain = ST_ACCEL_3_FS_AVL_2_GAIN,
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = ST_ACCEL_3_FS_AVL_4_VAL,
.gain = ST_ACCEL_3_FS_AVL_4_GAIN,
},
[2] = {
.num = ST_ACCEL_FS_AVL_6G,
.value = ST_ACCEL_3_FS_AVL_6_VAL,
.gain = ST_ACCEL_3_FS_AVL_6_GAIN,
},
[3] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = ST_ACCEL_3_FS_AVL_8_VAL,
.gain = ST_ACCEL_3_FS_AVL_8_GAIN,
},
[4] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = ST_ACCEL_3_FS_AVL_16_VAL,
.gain = ST_ACCEL_3_FS_AVL_16_GAIN,
},
},
},
.bdu = {
.addr = ST_ACCEL_3_BDU_ADDR,
.mask = ST_ACCEL_3_BDU_MASK,
},
.drdy_irq = {
.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
.ig1 = {
.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
.en_mask = ST_ACCEL_3_IG1_EN_MASK,
},
},
.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
.bootime = 2,
},
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val,
int *val2, long mask)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = st_sensors_read_info_raw(indio_dev, ch, val);
if (err < 0)
goto read_error;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = adata->current_fullscale->gain;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = adata->odr;
return IIO_VAL_INT;
default:
return -EINVAL;
}
read_error:
return err;
}
static int st_accel_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
int err;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (val2)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
err = st_sensors_set_odr(indio_dev, val);
mutex_unlock(&indio_dev->mlock);
return err;
default:
return -EINVAL;
}
return err;
}
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
static struct attribute *st_accel_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group st_accel_attribute_group = {
.attrs = st_accel_attributes,
};
static const struct iio_info accel_info = {
.driver_module = THIS_MODULE,
.attrs = &st_accel_attribute_group,
.read_raw = &st_accel_read_raw,
.write_raw = &st_accel_write_raw,
};
#ifdef CONFIG_IIO_TRIGGER
static const struct iio_trigger_ops st_accel_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
};
#define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops)
#else
#define ST_ACCEL_TRIGGER_OPS NULL
#endif
int st_accel_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *plat_data)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
int irq = adata->get_irq_data_ready(indio_dev);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &accel_info;
st_sensors_power_enable(indio_dev);
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
if (err < 0)
return err;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor->multi_read_bit;
indio_dev->channels = adata->sensor->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
adata->current_fullscale = (struct st_sensor_fullscale_avl *)
&adata->sensor->fs.fs_avl[0];
adata->odr = adata->sensor->odr.odr_avl[0].hz;
if (!plat_data)
plat_data =
(struct st_sensors_platform_data *)&default_accel_pdata;
err = st_sensors_init_sensor(indio_dev, plat_data);
if (err < 0)
return err;
err = st_accel_allocate_ring(indio_dev);
if (err < 0)
return err;
if (irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
ST_ACCEL_TRIGGER_OPS);
if (err < 0)
goto st_accel_probe_trigger_error;
}
err = iio_device_register(indio_dev);
if (err)
goto st_accel_device_register_error;
dev_info(&indio_dev->dev, "registered accelerometer %s\n",
indio_dev->name);
return 0;
st_accel_device_register_error:
if (irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
st_accel_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_accel_common_probe);
void st_accel_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
st_sensors_power_disable(indio_dev);
iio_device_unregister(indio_dev);
if (adata->get_irq_data_ready(indio_dev) > 0)
st_sensors_deallocate_trigger(indio_dev);
st_accel_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_accel_common_remove);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,130 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/st_sensors.h>
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_accel.h"
#ifdef CONFIG_OF
static const struct of_device_id st_accel_of_match[] = {
{
.compatible = "st,lsm303dlh-accel",
.data = LSM303DLH_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303dlhc-accel",
.data = LSM303DLHC_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3dh-accel",
.data = LIS3DH_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm330d-accel",
.data = LSM330D_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm330dl-accel",
.data = LSM330DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm330dlc-accel",
.data = LSM330DLC_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis331dlh-accel",
.data = LIS331DLH_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303dl-accel",
.data = LSM303DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303dlm-accel",
.data = LSM303DLM_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm330-accel",
.data = LSM330_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
#else
#define st_accel_of_match NULL
#endif
static int st_accel_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct st_sensor_data *adata;
int err;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
if (!indio_dev)
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &client->dev;
st_sensors_of_i2c_probe(client, st_accel_of_match);
st_sensors_i2c_configure(indio_dev, client, adata);
err = st_accel_common_probe(indio_dev, client->dev.platform_data);
if (err < 0)
return err;
return 0;
}
static int st_accel_i2c_remove(struct i2c_client *client)
{
st_accel_common_remove(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DLH_ACCEL_DEV_NAME },
{ LSM303DLHC_ACCEL_DEV_NAME },
{ LIS3DH_ACCEL_DEV_NAME },
{ LSM330D_ACCEL_DEV_NAME },
{ LSM330DL_ACCEL_DEV_NAME },
{ LSM330DLC_ACCEL_DEV_NAME },
{ LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
static struct i2c_driver st_accel_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-accel-i2c",
.of_match_table = of_match_ptr(st_accel_of_match),
},
.probe = st_accel_i2c_probe,
.remove = st_accel_i2c_remove,
.id_table = st_accel_id_table,
};
module_i2c_driver(st_accel_driver);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,78 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/st_sensors.h>
#include <linux/iio/common/st_sensors_spi.h>
#include "st_accel.h"
static int st_accel_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct st_sensor_data *adata;
int err;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata));
if (!indio_dev)
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, adata);
err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
if (err < 0)
return err;
return 0;
}
static int st_accel_spi_remove(struct spi_device *spi)
{
st_accel_common_remove(spi_get_drvdata(spi));
return 0;
}
static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DLH_ACCEL_DEV_NAME },
{ LSM303DLHC_ACCEL_DEV_NAME },
{ LIS3DH_ACCEL_DEV_NAME },
{ LSM330D_ACCEL_DEV_NAME },
{ LSM330DL_ACCEL_DEV_NAME },
{ LSM330DLC_ACCEL_DEV_NAME },
{ LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
static struct spi_driver st_accel_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-accel-spi",
},
.probe = st_accel_spi_probe,
.remove = st_accel_spi_remove,
.id_table = st_accel_id_table,
};
module_spi_driver(st_accel_driver);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver");
MODULE_LICENSE("GPL v2");

302
drivers/iio/adc/Kconfig Normal file
View file

@ -0,0 +1,302 @@
#
# ADC drivers
#
# When adding new entries keep the list in alphabetical order
menu "Analog to digital converters"
config AD_SIGMA_DELTA
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7266
tristate "Analog Devices AD7265/AD7266 ADC driver"
depends on SPI_MASTER
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs.
config AD7291
tristate "Analog Devices AD7291 ADC driver"
depends on I2C
help
Say yes here to build support for Analog Devices AD7291
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7291.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7298
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7298.
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7476.
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say
N (but it is safe to say "Y").
To compile this driver as a module, choose M here: the module will be
called ad7791.
config AD7793
tristate "Analog Devices AD7793 and similar ADCs driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
AD7794 and AD7795 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called AD7793.
config AD7887
tristate "Analog Devices AD7887 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7887 SPI analog to digital converter (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7887.
config AD7923
tristate "Analog Devices AD7923 and similar ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
To compile this driver as a module, choose M here: the
module will be called ad7923.
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices:
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
i2c analog to digital converters (ADC). Provides direct access
via sysfs.
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91
depends on INPUT
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select SYSFS
help
Say yes here to build support for Atmel AT91 ADC.
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
help
Core support for the ADC block found in the Samsung EXYNOS series
of SoCs for drivers such as the touchscreen and hwmon to use to share
this resource.
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
help
Say yes here to build support for TI LP8788 ADC.
config MAX1027
tristate "Maxim max1027 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Maxim SPI ADC models
max1027, max1029 and max1031.
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
select IIO_BUFFER
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,
max1037, max1038, max1039, max1136, max1136, max1137, max1138,
max1139, max1236, max1237, max11238, max1239, max11600, max11601,
max11602, max11603, max11604, max11605, max11606, max11607,
max11608, max11609, max11610, max11611, max11612, max11613,
max11614, max11615, max11616, max11617, max11644, max11645,
max11646, max11647) Provides direct access via sysfs and buffered
data via the iio dev interface.
config MCP320X
tristate "Microchip Technology MCP3204/08"
depends on SPI
help
Say yes here to build support for Microchip Technology's MCP3204 or
MCP3208 analog to digital converter.
This driver can also be built as a module. If so, the module will be
called mcp320x.
config MCP3422
tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
depends on I2C
help
Say yes here to build support for Microchip Technology's
MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428
analog to digital converters.
This driver can also be built as a module. If so, the module will be
called mcp3422.
config MEN_Z188_ADC
tristate "MEN 16z188 ADC IP Core support"
depends on MCB
help
Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB
carrier.
This driver can also be built as a module. If so, the module will be
called men_z188_adc.
config NAU7802
tristate "Nuvoton NAU7802 ADC driver"
depends on I2C
help
Say yes here to build support for Nuvoton NAU7802 ADC.
To compile this driver as a module, choose M here: the
module will be called nau7802.
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
help
Say yes here to build support for the SARADC found in SoCs from
Rockchip.
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
config TI_ADC081C
tristate "Texas Instruments ADC081C021/027"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADC081C021
and ADC081C027 ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-adc081c.
config TI_ADC128S052
tristate "Texas Instruments ADC128S052"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC128S052
chip.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC
select IIO_BUFFER
select IIO_KFIFO_BUF
help
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
help
This driver provides support for Triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can also be built as a module. If so, the module will be
called twl4030-madc.
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
default n
help
Say yes here if you want support for the TWL6030/TWL6032 General
Purpose A/D Converter. This will add support for battery type
detection, battery voltage and temperature measurement, die
temperature measurement, system supply voltage, audio accessory,
USB ID detection.
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on OF
help
Say yes here to support for Vybrid board analog-to-digital converter.
Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
This driver can also be built as a module. If so, the module will be
called vf610_adc.
config VIPERBOARD_ADC
tristate "Viperboard ADC support"
depends on MFD_VIPERBOARD && USB
help
Say yes here to access the ADC part of the Nano River
Technologies Viperboard.
config XILINX_XADC
tristate "Xilinx XADC driver"
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
depends on HAS_IOMEM
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to have support for the Xilinx XADC. The driver does support
both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
The driver can also be build as a module. If so, the module will be called
xilinx-xadc.
endmenu

34
drivers/iio/adc/Makefile Normal file
View file

@ -0,0 +1,34 @@
#
# Makefile for IIO ADC drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o

522
drivers/iio/adc/ad7266.c Normal file
View file

@ -0,0 +1,522 @@
/*
* AD7266/65 SPI ADC driver
*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/platform_data/ad7266.h>
struct ad7266_state {
struct spi_device *spi;
struct regulator *reg;
unsigned long vref_mv;
struct spi_transfer single_xfer[3];
struct spi_message single_msg;
enum ad7266_range range;
enum ad7266_mode mode;
bool fixed_addr;
struct gpio gpios[3];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* The buffer needs to be large enough to hold two samples (4 bytes) and
* the naturally aligned timestamp (8 bytes).
*/
struct {
__be16 sample[2];
s64 timestamp;
} data ____cacheline_aligned;
};
static int ad7266_wakeup(struct ad7266_state *st)
{
/* Any read with >= 2 bytes will wake the device */
return spi_read(st->spi, &st->data.sample[0], 2);
}
static int ad7266_powerdown(struct ad7266_state *st)
{
/* Any read with < 2 bytes will powerdown the device */
return spi_read(st->spi, &st->data.sample[0], 1);
}
static int ad7266_preenable(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
return ad7266_wakeup(st);
}
static int ad7266_postdisable(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
return ad7266_powerdown(st);
}
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
.preenable = &ad7266_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad7266_postdisable,
};
static irqreturn_t ad7266_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
ret = spi_read(st->spi, st->data.sample, 4);
if (ret == 0) {
iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
pf->timestamp);
}
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static void ad7266_select_input(struct ad7266_state *st, unsigned int nr)
{
unsigned int i;
if (st->fixed_addr)
return;
switch (st->mode) {
case AD7266_MODE_SINGLE_ENDED:
nr >>= 1;
break;
case AD7266_MODE_PSEUDO_DIFF:
nr |= 1;
break;
case AD7266_MODE_DIFF:
nr &= ~1;
break;
}
for (i = 0; i < 3; ++i)
gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i)));
}
static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad7266_state *st = iio_priv(indio_dev);
unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength);
ad7266_select_input(st, nr);
return 0;
}
static int ad7266_read_single(struct ad7266_state *st, int *val,
unsigned int address)
{
int ret;
ad7266_select_input(st, address);
ret = spi_sync(st->spi, &st->single_msg);
*val = be16_to_cpu(st->data.sample[address % 2]);
return ret;
}
static int ad7266_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long m)
{
struct ad7266_state *st = iio_priv(indio_dev);
unsigned long scale_mv;
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = ad7266_read_single(st, val, chan->address);
if (ret)
return ret;
*val = (*val >> 2) & 0xfff;
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_mv = st->vref_mv;
if (st->mode == AD7266_MODE_DIFF)
scale_mv *= 2;
if (st->range == AD7266_RANGE_2VREF)
scale_mv *= 2;
*val = scale_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
if (st->range == AD7266_RANGE_2VREF &&
st->mode != AD7266_MODE_DIFF)
*val = 2048;
else
*val = 0;
return IIO_VAL_INT;
}
return -EINVAL;
}
#define AD7266_CHAN(_chan, _sign) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = (_sign), \
.realbits = 12, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
}
#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS(_name, _sign) \
const struct iio_chan_spec ad7266_channels_##_name[] = { \
AD7266_CHAN(0, (_sign)), \
AD7266_CHAN(1, (_sign)), \
AD7266_CHAN(2, (_sign)), \
AD7266_CHAN(3, (_sign)), \
AD7266_CHAN(4, (_sign)), \
AD7266_CHAN(5, (_sign)), \
AD7266_CHAN(6, (_sign)), \
AD7266_CHAN(7, (_sign)), \
AD7266_CHAN(8, (_sign)), \
AD7266_CHAN(9, (_sign)), \
AD7266_CHAN(10, (_sign)), \
AD7266_CHAN(11, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(13), \
}
#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(_name, _sign) \
const struct iio_chan_spec ad7266_channels_##_name##_fixed[] = { \
AD7266_CHAN(0, (_sign)), \
AD7266_CHAN(1, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(u, 'u');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(s, 's');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(u, 'u');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's');
#define AD7266_CHAN_DIFF(_chan, _sign) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2, \
.channel2 = (_chan) * 2 + 1, \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = _sign, \
.realbits = 12, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
.differential = 1, \
}
#define AD7266_DECLARE_DIFF_CHANNELS(_name, _sign) \
const struct iio_chan_spec ad7266_channels_diff_##_name[] = { \
AD7266_CHAN_DIFF(0, (_sign)), \
AD7266_CHAN_DIFF(1, (_sign)), \
AD7266_CHAN_DIFF(2, (_sign)), \
AD7266_CHAN_DIFF(3, (_sign)), \
AD7266_CHAN_DIFF(4, (_sign)), \
AD7266_CHAN_DIFF(5, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(6), \
}
static AD7266_DECLARE_DIFF_CHANNELS(s, 's');
static AD7266_DECLARE_DIFF_CHANNELS(u, 'u');
#define AD7266_DECLARE_DIFF_CHANNELS_FIXED(_name, _sign) \
const struct iio_chan_spec ad7266_channels_diff_fixed_##_name[] = { \
AD7266_CHAN_DIFF(0, (_sign)), \
AD7266_CHAN_DIFF(1, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
static AD7266_DECLARE_DIFF_CHANNELS_FIXED(s, 's');
static AD7266_DECLARE_DIFF_CHANNELS_FIXED(u, 'u');
static const struct iio_info ad7266_info = {
.read_raw = &ad7266_read_raw,
.update_scan_mode = &ad7266_update_scan_mode,
.driver_module = THIS_MODULE,
};
static const unsigned long ad7266_available_scan_masks[] = {
0x003,
0x00c,
0x030,
0x0c0,
0x300,
0xc00,
0x000,
};
static const unsigned long ad7266_available_scan_masks_diff[] = {
0x003,
0x00c,
0x030,
0x000,
};
static const unsigned long ad7266_available_scan_masks_fixed[] = {
0x003,
0x000,
};
struct ad7266_chan_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
const unsigned long *scan_masks;
};
#define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \
(((_differential) << 2) | ((_signed) << 1) | ((_fixed) << 0))
static const struct ad7266_chan_info ad7266_chan_infos[] = {
[AD7266_CHAN_INFO_INDEX(0, 0, 0)] = {
.channels = ad7266_channels_u,
.num_channels = ARRAY_SIZE(ad7266_channels_u),
.scan_masks = ad7266_available_scan_masks,
},
[AD7266_CHAN_INFO_INDEX(0, 0, 1)] = {
.channels = ad7266_channels_u_fixed,
.num_channels = ARRAY_SIZE(ad7266_channels_u_fixed),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(0, 1, 0)] = {
.channels = ad7266_channels_s,
.num_channels = ARRAY_SIZE(ad7266_channels_s),
.scan_masks = ad7266_available_scan_masks,
},
[AD7266_CHAN_INFO_INDEX(0, 1, 1)] = {
.channels = ad7266_channels_s_fixed,
.num_channels = ARRAY_SIZE(ad7266_channels_s_fixed),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(1, 0, 0)] = {
.channels = ad7266_channels_diff_u,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_u),
.scan_masks = ad7266_available_scan_masks_diff,
},
[AD7266_CHAN_INFO_INDEX(1, 0, 1)] = {
.channels = ad7266_channels_diff_fixed_u,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_u),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(1, 1, 0)] = {
.channels = ad7266_channels_diff_s,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_s),
.scan_masks = ad7266_available_scan_masks_diff,
},
[AD7266_CHAN_INFO_INDEX(1, 1, 1)] = {
.channels = ad7266_channels_diff_fixed_s,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_s),
.scan_masks = ad7266_available_scan_masks_fixed,
},
};
static void ad7266_init_channels(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
bool is_differential, is_signed;
const struct ad7266_chan_info *chan_info;
int i;
is_differential = st->mode != AD7266_MODE_SINGLE_ENDED;
is_signed = (st->range == AD7266_RANGE_2VREF) |
(st->mode == AD7266_MODE_DIFF);
i = AD7266_CHAN_INFO_INDEX(is_differential, is_signed, st->fixed_addr);
chan_info = &ad7266_chan_infos[i];
indio_dev->channels = chan_info->channels;
indio_dev->num_channels = chan_info->num_channels;
indio_dev->available_scan_masks = chan_info->scan_masks;
indio_dev->masklength = chan_info->num_channels - 1;
}
static const char * const ad7266_gpio_labels[] = {
"AD0", "AD1", "AD2",
};
static int ad7266_probe(struct spi_device *spi)
{
struct ad7266_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad7266_state *st;
unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vref");
if (!IS_ERR_OR_NULL(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
st->vref_mv = ret / 1000;
} else {
/* Use internal reference */
st->vref_mv = 2500;
}
if (pdata) {
st->fixed_addr = pdata->fixed_addr;
st->mode = pdata->mode;
st->range = pdata->range;
if (!st->fixed_addr) {
for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) {
st->gpios[i].gpio = pdata->addr_gpios[i];
st->gpios[i].flags = GPIOF_OUT_INIT_LOW;
st->gpios[i].label = ad7266_gpio_labels[i];
}
ret = gpio_request_array(st->gpios,
ARRAY_SIZE(st->gpios));
if (ret)
goto error_disable_reg;
}
} else {
st->fixed_addr = true;
st->range = AD7266_RANGE_VREF;
st->mode = AD7266_MODE_DIFF;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7266_info;
ad7266_init_channels(indio_dev);
/* wakeup */
st->single_xfer[0].rx_buf = &st->data.sample[0];
st->single_xfer[0].len = 2;
st->single_xfer[0].cs_change = 1;
/* conversion */
st->single_xfer[1].rx_buf = st->data.sample;
st->single_xfer[1].len = 4;
st->single_xfer[1].cs_change = 1;
/* powerdown */
st->single_xfer[2].tx_buf = &st->data.sample[0];
st->single_xfer[2].len = 1;
spi_message_init(&st->single_msg);
spi_message_add_tail(&st->single_xfer[0], &st->single_msg);
spi_message_add_tail(&st->single_xfer[1], &st->single_msg);
spi_message_add_tail(&st->single_xfer[2], &st->single_msg);
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops);
if (ret)
goto error_free_gpios;
ret = iio_device_register(indio_dev);
if (ret)
goto error_buffer_cleanup;
return 0;
error_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
error_free_gpios:
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
if (!IS_ERR_OR_NULL(st->reg))
regulator_disable(st->reg);
return ret;
}
static int ad7266_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7266_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
if (!IS_ERR_OR_NULL(st->reg))
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7266_id[] = {
{"ad7265", 0},
{"ad7266", 0},
{ }
};
MODULE_DEVICE_TABLE(spi, ad7266_id);
static struct spi_driver ad7266_driver = {
.driver = {
.name = "ad7266",
.owner = THIS_MODULE,
},
.probe = ad7266_probe,
.remove = ad7266_remove,
.id_table = ad7266_id,
};
module_spi_driver(ad7266_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD7266/65 ADC");
MODULE_LICENSE("GPL v2");

585
drivers/iio/adc/ad7291.c Normal file
View file

@ -0,0 +1,585 @@
/*
* AD7291 8-Channel, I2C, 12-Bit SAR ADC with Temperature Sensor
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/platform_data/ad7291.h>
/*
* Simplified handling
*
* If no events enabled - single polled channel read
* If event enabled direct reads disable unless channel
* is in the read mask.
*
* The noise-delayed bit as per datasheet suggestion is always enabled.
*/
/*
* AD7291 registers definition
*/
#define AD7291_COMMAND 0x00
#define AD7291_VOLTAGE 0x01
#define AD7291_T_SENSE 0x02
#define AD7291_T_AVERAGE 0x03
#define AD7291_DATA_HIGH(x) ((x) * 3 + 0x4)
#define AD7291_DATA_LOW(x) ((x) * 3 + 0x5)
#define AD7291_HYST(x) ((x) * 3 + 0x6)
#define AD7291_VOLTAGE_ALERT_STATUS 0x1F
#define AD7291_T_ALERT_STATUS 0x20
#define AD7291_BITS 12
#define AD7291_VOLTAGE_LIMIT_COUNT 8
/*
* AD7291 command
*/
#define AD7291_AUTOCYCLE BIT(0)
#define AD7291_RESET BIT(1)
#define AD7291_ALERT_CLEAR BIT(2)
#define AD7291_ALERT_POLARITY BIT(3)
#define AD7291_EXT_REF BIT(4)
#define AD7291_NOISE_DELAY BIT(5)
#define AD7291_T_SENSE_MASK BIT(7)
#define AD7291_VOLTAGE_MASK GENMASK(15, 8)
#define AD7291_VOLTAGE_OFFSET 8
/*
* AD7291 value masks
*/
#define AD7291_VALUE_MASK GENMASK(11, 0)
/*
* AD7291 alert register bits
*/
#define AD7291_T_LOW BIT(0)
#define AD7291_T_HIGH BIT(1)
#define AD7291_T_AVG_LOW BIT(2)
#define AD7291_T_AVG_HIGH BIT(3)
#define AD7291_V_LOW(x) BIT((x) * 2)
#define AD7291_V_HIGH(x) BIT((x) * 2 + 1)
struct ad7291_chip_info {
struct i2c_client *client;
struct regulator *reg;
u16 command;
u16 c_mask; /* Active voltage channels for events */
struct mutex state_lock;
};
static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data)
{
struct i2c_client *client = chip->client;
int ret = 0;
ret = i2c_smbus_read_word_swapped(client, reg);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
*data = ret;
return 0;
}
static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data)
{
return i2c_smbus_write_word_swapped(chip->client, reg, data);
}
static irqreturn_t ad7291_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad7291_chip_info *chip = iio_priv(private);
u16 t_status, v_status;
u16 command;
int i;
s64 timestamp = iio_get_time_ns();
if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
return IRQ_HANDLED;
if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status))
return IRQ_HANDLED;
if (!(t_status || v_status))
return IRQ_HANDLED;
command = chip->command | AD7291_ALERT_CLEAR;
ad7291_i2c_write(chip, AD7291_COMMAND, command);
command = chip->command & ~AD7291_ALERT_CLEAR;
ad7291_i2c_write(chip, AD7291_COMMAND, command);
/* For now treat t_sense and t_sense_average the same */
if ((t_status & AD7291_T_LOW) || (t_status & AD7291_T_AVG_LOW))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
timestamp);
if ((t_status & AD7291_T_HIGH) || (t_status & AD7291_T_AVG_HIGH))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
if (v_status & AD7291_V_LOW(i))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
timestamp);
if (v_status & AD7291_V_HIGH(i))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
}
return IRQ_HANDLED;
}
static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
enum iio_event_direction dir,
enum iio_event_info info)
{
unsigned int offset;
switch (chan->type) {
case IIO_VOLTAGE:
offset = chan->channel;
break;
case IIO_TEMP:
offset = AD7291_VOLTAGE_OFFSET;
break;
default:
return 0;
}
switch (info) {
case IIO_EV_INFO_VALUE:
if (dir == IIO_EV_DIR_FALLING)
return AD7291_DATA_HIGH(offset);
else
return AD7291_DATA_LOW(offset);
case IIO_EV_INFO_HYSTERESIS:
return AD7291_HYST(offset);
default:
break;
}
return 0;
}
static int ad7291_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
int ret;
u16 uval;
ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info),
&uval);
if (ret < 0)
return ret;
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE)
*val = uval & AD7291_VALUE_MASK;
else
*val = sign_extend32(uval, 11);
return IIO_VAL_INT;
}
static int ad7291_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) {
if (val > AD7291_VALUE_MASK || val < 0)
return -EINVAL;
} else {
if (val > 2047 || val < -2048)
return -EINVAL;
}
return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info),
val);
}
static int ad7291_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
/*
* To be enabled the channel must simply be on. If any are enabled
* we are in continuous sampling mode
*/
switch (chan->type) {
case IIO_VOLTAGE:
return !!(chip->c_mask & BIT(15 - chan->channel));
case IIO_TEMP:
/* always on */
return 1;
default:
return -EINVAL;
}
}
static int ad7291_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
int ret = 0;
struct ad7291_chip_info *chip = iio_priv(indio_dev);
unsigned int mask;
u16 regval;
mutex_lock(&chip->state_lock);
regval = chip->command;
/*
* To be enabled the channel must simply be on. If any are enabled
* use continuous sampling mode.
* Possible to disable temp as well but that makes single read tricky.
*/
mask = BIT(15 - chan->channel);
switch (chan->type) {
case IIO_VOLTAGE:
if ((!state) && (chip->c_mask & mask))
chip->c_mask &= ~mask;
else if (state && (!(chip->c_mask & mask)))
chip->c_mask |= mask;
else
break;
regval &= ~AD7291_AUTOCYCLE;
regval |= chip->c_mask;
if (chip->c_mask) /* Enable autocycle? */
regval |= AD7291_AUTOCYCLE;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval);
if (ret < 0)
goto error_ret;
chip->command = regval;
break;
default:
ret = -EINVAL;
}
error_ret:
mutex_unlock(&chip->state_lock);
return ret;
}
static int ad7291_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
int ret;
struct ad7291_chip_info *chip = iio_priv(indio_dev);
u16 regval;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&chip->state_lock);
/* If in autocycle mode drop through */
if (chip->command & AD7291_AUTOCYCLE) {
mutex_unlock(&chip->state_lock);
return -EBUSY;
}
/* Enable this channel alone */
regval = chip->command & (~AD7291_VOLTAGE_MASK);
regval |= BIT(15 - chan->channel);
ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
/* Read voltage */
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_VOLTAGE);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
*val = ret & AD7291_VALUE_MASK;
mutex_unlock(&chip->state_lock);
return IIO_VAL_INT;
case IIO_TEMP:
/* Assumes tsense bit of command register always set */
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_T_SENSE);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 11);
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_AVERAGE_RAW:
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_T_AVERAGE);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
if (chip->reg) {
int vref;
vref = regulator_get_voltage(chip->reg);
if (vref < 0)
return vref;
*val = vref / 1000;
} else {
*val = 2500;
}
*val2 = AD7291_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
/*
* One LSB of the ADC corresponds to 0.25 deg C.
* The temperature reading is in 12-bit twos
* complement format
*/
*val = 250;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_event_spec ad7291_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define AD7291_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = _chan, \
.event_spec = ad7291_events, \
.num_event_specs = ARRAY_SIZE(ad7291_events), \
}
static const struct iio_chan_spec ad7291_channels[] = {
AD7291_VOLTAGE_CHAN(0),
AD7291_VOLTAGE_CHAN(1),
AD7291_VOLTAGE_CHAN(2),
AD7291_VOLTAGE_CHAN(3),
AD7291_VOLTAGE_CHAN(4),
AD7291_VOLTAGE_CHAN(5),
AD7291_VOLTAGE_CHAN(6),
AD7291_VOLTAGE_CHAN(7),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = 0,
.event_spec = ad7291_events,
.num_event_specs = ARRAY_SIZE(ad7291_events),
}
};
static const struct iio_info ad7291_info = {
.read_raw = &ad7291_read_raw,
.read_event_config = &ad7291_read_event_config,
.write_event_config = &ad7291_write_event_config,
.read_event_value = &ad7291_read_event_value,
.write_event_value = &ad7291_write_event_value,
.driver_module = THIS_MODULE,
};
static int ad7291_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ad7291_platform_data *pdata = client->dev.platform_data;
struct ad7291_chip_info *chip;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
chip = iio_priv(indio_dev);
if (pdata && pdata->use_external_ref) {
chip->reg = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(chip->reg))
return PTR_ERR(chip->reg);
ret = regulator_enable(chip->reg);
if (ret)
return ret;
}
mutex_init(&chip->state_lock);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
chip->client = client;
chip->command = AD7291_NOISE_DELAY |
AD7291_T_SENSE_MASK | /* Tsense always enabled */
AD7291_ALERT_POLARITY; /* set irq polarity low level */
if (pdata && pdata->use_external_ref)
chip->command |= AD7291_EXT_REF;
indio_dev->name = id->name;
indio_dev->channels = ad7291_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7291_channels);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ad7291_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, AD7291_RESET);
if (ret) {
ret = -EIO;
goto error_disable_reg;
}
ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command);
if (ret) {
ret = -EIO;
goto error_disable_reg;
}
if (client->irq > 0) {
ret = request_threaded_irq(client->irq,
NULL,
&ad7291_event_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
id->name,
indio_dev);
if (ret)
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_irq;
return 0;
error_unreg_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
error_disable_reg:
if (chip->reg)
regulator_disable(chip->reg);
return ret;
}
static int ad7291_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (client->irq)
free_irq(client->irq, indio_dev);
if (chip->reg)
regulator_disable(chip->reg);
return 0;
}
static const struct i2c_device_id ad7291_id[] = {
{ "ad7291", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ad7291_id);
static struct i2c_driver ad7291_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = ad7291_probe,
.remove = ad7291_remove,
.id_table = ad7291_id,
};
module_i2c_driver(ad7291_driver);
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7291 ADC driver");
MODULE_LICENSE("GPL v2");

391
drivers/iio/adc/ad7298.c Normal file
View file

@ -0,0 +1,391 @@
/*
* AD7298 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/platform_data/ad7298.h>
#define AD7298_WRITE BIT(15) /* write to the control register */
#define AD7298_REPEAT BIT(14) /* repeated conversion enable */
#define AD7298_CH(x) BIT(13 - (x)) /* channel select */
#define AD7298_TSENSE BIT(5) /* temperature conversion enable */
#define AD7298_EXTREF BIT(2) /* external reference enable */
#define AD7298_TAVG BIT(1) /* temperature sensor averaging enable */
#define AD7298_PDD BIT(0) /* partial power down enable */
#define AD7298_MAX_CHAN 8
#define AD7298_INTREF_mV 2500
#define AD7298_CH_TEMP 9
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
struct spi_transfer scan_single_xfer[3];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 rx_buf[12] ____cacheline_aligned;
__be16 tx_buf[2];
};
#define AD7298_V_CHAN(index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec ad7298_channels[] = {
{
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = AD7298_CH_TEMP,
.scan_index = -1,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
},
},
AD7298_V_CHAN(0),
AD7298_V_CHAN(1),
AD7298_V_CHAN(2),
AD7298_V_CHAN(3),
AD7298_V_CHAN(4),
AD7298_V_CHAN(5),
AD7298_V_CHAN(6),
AD7298_V_CHAN(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
/**
* ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7298_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7298_state *st = iio_priv(indio_dev);
int i, m;
unsigned short command;
int scan_count;
/* Now compute overall size */
scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
if (test_bit(i, active_scan_mask))
command |= m;
st->tx_buf[0] = cpu_to_be16(command);
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = 2;
st->ring_xfer[0].cs_change = 1;
st->ring_xfer[1].tx_buf = &st->tx_buf[1];
st->ring_xfer[1].len = 2;
st->ring_xfer[1].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
for (i = 0; i < scan_count; i++) {
st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 2].len = 2;
st->ring_xfer[i + 2].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7298_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7298_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
{
int ret;
st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref |
(AD7298_CH(0) >> ch));
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
return be16_to_cpu(st->rx_buf[0]);
}
static int ad7298_scan_temp(struct ad7298_state *st, int *val)
{
int ret;
__be16 buf;
buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
AD7298_TAVG | st->ext_ref);
ret = spi_write(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
buf = cpu_to_be16(0);
ret = spi_write(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
usleep_range(101, 1000); /* sleep > 100us */
ret = spi_read(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
*val = sign_extend32(be16_to_cpu(buf), 11);
return 0;
}
static int ad7298_get_ref_voltage(struct ad7298_state *st)
{
int vref;
if (st->ext_ref) {
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
return vref / 1000;
} else {
return AD7298_INTREF_mV;
}
}
static int ad7298_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7298_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
} else {
if (chan->address == AD7298_CH_TEMP)
ret = ad7298_scan_temp(st, val);
else
ret = ad7298_scan_direct(st, chan->address);
}
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
if (chan->address != AD7298_CH_TEMP)
*val = ret & GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
*val = ad7298_get_ref_voltage(st);
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
*val = ad7298_get_ref_voltage(st);
*val2 = 10;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 1093 - 2732500 / ad7298_get_ref_voltage(st);
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info ad7298_info = {
.read_raw = &ad7298_read_raw,
.update_scan_mode = ad7298_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int ad7298_probe(struct spi_device *spi)
{
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (pdata && pdata->ext_ref)
st->ext_ref = AD7298_EXTREF;
if (st->ext_ref) {
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad7298_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7298_channels);
indio_dev->info = &ad7298_info;
/* Setup default message */
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].tx_buf = &st->tx_buf[1];
st->scan_single_xfer[1].len = 2;
st->scan_single_xfer[1].cs_change = 1;
st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[2].len = 2;
spi_message_init(&st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7298_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (st->ext_ref)
regulator_disable(st->reg);
return ret;
}
static int ad7298_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7298_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (st->ext_ref)
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7298_id[] = {
{"ad7298", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ad7298_id);
static struct spi_driver ad7298_driver = {
.driver = {
.name = "ad7298",
.owner = THIS_MODULE,
},
.probe = ad7298_probe,
.remove = ad7298_remove,
.id_table = ad7298_id,
};
module_spi_driver(ad7298_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
MODULE_LICENSE("GPL v2");

315
drivers/iio/adc/ad7476.c Normal file
View file

@ -0,0 +1,315 @@
/*
* AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
struct ad7476_state;
struct ad7476_chip_info {
unsigned int int_vref_uv;
struct iio_chan_spec channel[2];
void (*reset)(struct ad7476_state *);
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
struct spi_transfer xfer;
struct spi_message msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* Make the buffer large enough for one 16 bit sample and one 64 bit
* aligned 64 bit timestamp.
*/
unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)]
____cacheline_aligned;
};
enum ad7476_supported_device_ids {
ID_AD7091R,
ID_AD7276,
ID_AD7277,
ID_AD7278,
ID_AD7466,
ID_AD7467,
ID_AD7468,
ID_AD7495,
ID_AD7940,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7476_state *st = iio_priv(indio_dev);
int b_sent;
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static void ad7091_reset(struct ad7476_state *st)
{
/* Any transfers with 8 scl cycles will reset the device */
spi_read(st->spi, st->data, 1);
}
static int ad7476_scan_direct(struct ad7476_state *st)
{
int ret;
ret = spi_sync(st->spi, &st->msg);
if (ret)
return ret;
return be16_to_cpup((__be16 *)st->data);
}
static int ad7476_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7476_state *st = iio_priv(indio_dev);
int scale_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7476_scan_direct(st);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (!st->chip_info->int_vref_uv) {
scale_uv = regulator_get_voltage(st->reg);
if (scale_uv < 0)
return scale_uv;
} else {
scale_uv = st->chip_info->int_vref_uv;
}
*val = scale_uv / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
#define _AD7476_CHAN(bits, _shift, _info_mask_sep) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.info_mask_separate = _info_mask_sep, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = (_shift), \
.endianness = IIO_BE, \
}, \
}
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7091R] = {
.channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.reset = ad7091_reset,
},
[ID_AD7276] = {
.channel[0] = AD7940_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7277] = {
.channel[0] = AD7940_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7278] = {
.channel[0] = AD7940_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7466] = {
.channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7467] = {
.channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7468] = {
.channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7495] = {
.channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_uv = 2500000,
},
[ID_AD7940] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
};
static const struct iio_info ad7476_info = {
.driver_module = THIS_MODULE,
.read_raw = &ad7476_read_raw,
};
static int ad7476_probe(struct spi_device *spi)
{
struct ad7476_state *st;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
/* Establish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = 2;
indio_dev->info = &ad7476_info;
/* Setup default message */
st->xfer.rx_buf = &st->data;
st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &st->msg);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7476_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
if (st->chip_info->reset)
st->chip_info->reset(st);
ret = iio_device_register(indio_dev);
if (ret)
goto error_ring_unregister;
return 0;
error_ring_unregister:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad7476_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7476_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7476_id[] = {
{"ad7091r", ID_AD7091R},
{"ad7273", ID_AD7277},
{"ad7274", ID_AD7276},
{"ad7276", ID_AD7276},
{"ad7277", ID_AD7277},
{"ad7278", ID_AD7278},
{"ad7466", ID_AD7466},
{"ad7467", ID_AD7467},
{"ad7468", ID_AD7468},
{"ad7475", ID_AD7466},
{"ad7476", ID_AD7466},
{"ad7476a", ID_AD7466},
{"ad7477", ID_AD7467},
{"ad7477a", ID_AD7467},
{"ad7478", ID_AD7468},
{"ad7478a", ID_AD7468},
{"ad7495", ID_AD7495},
{"ad7910", ID_AD7467},
{"ad7920", ID_AD7466},
{"ad7940", ID_AD7940},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
static struct spi_driver ad7476_driver = {
.driver = {
.name = "ad7476",
.owner = THIS_MODULE,
},
.probe = ad7476_probe,
.remove = ad7476_remove,
.id_table = ad7476_id,
};
module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2");

453
drivers/iio/adc/ad7791.c Normal file
View file

@ -0,0 +1,453 @@
/*
* AD7787/AD7788/AD7789/AD7790/AD7791 SPI ADC driver
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <linux/platform_data/ad7791.h>
#define AD7791_REG_COMM 0x0 /* For writes */
#define AD7791_REG_STATUS 0x0 /* For reads */
#define AD7791_REG_MODE 0x1
#define AD7791_REG_FILTER 0x2
#define AD7791_REG_DATA 0x3
#define AD7791_MODE_CONTINUOUS 0x00
#define AD7791_MODE_SINGLE 0x02
#define AD7791_MODE_POWERDOWN 0x03
#define AD7791_CH_AIN1P_AIN1N 0x00
#define AD7791_CH_AIN2 0x01
#define AD7791_CH_AIN1N_AIN1N 0x02
#define AD7791_CH_AVDD_MONITOR 0x03
#define AD7791_FILTER_CLK_DIV_1 (0x0 << 4)
#define AD7791_FILTER_CLK_DIV_2 (0x1 << 4)
#define AD7791_FILTER_CLK_DIV_4 (0x2 << 4)
#define AD7791_FILTER_CLK_DIV_8 (0x3 << 4)
#define AD7791_FILTER_CLK_MASK (0x3 << 4)
#define AD7791_FILTER_RATE_120 0x0
#define AD7791_FILTER_RATE_100 0x1
#define AD7791_FILTER_RATE_33_3 0x2
#define AD7791_FILTER_RATE_20 0x3
#define AD7791_FILTER_RATE_16_6 0x4
#define AD7791_FILTER_RATE_16_7 0x5
#define AD7791_FILTER_RATE_13_3 0x6
#define AD7791_FILTER_RATE_9_5 0x7
#define AD7791_FILTER_RATE_MASK 0x7
#define AD7791_MODE_BUFFER BIT(1)
#define AD7791_MODE_UNIPOLAR BIT(2)
#define AD7791_MODE_BURNOUT BIT(3)
#define AD7791_MODE_SEL_MASK (0x3 << 6)
#define AD7791_MODE_SEL(x) ((x) << 6)
#define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \
const struct iio_chan_spec name[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \
AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR, \
(bits), (storagebits), 0), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \
const struct iio_chan_spec name[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \
(bits), (storagebits), 0), \
IIO_CHAN_SOFT_TIMESTAMP(3), \
}
static DECLARE_AD7787_CHANNELS(ad7787_channels, 24, 32);
static DECLARE_AD7791_CHANNELS(ad7790_channels, 16, 16);
static DECLARE_AD7791_CHANNELS(ad7791_channels, 24, 32);
enum {
AD7787,
AD7788,
AD7789,
AD7790,
AD7791,
};
enum ad7791_chip_info_flags {
AD7791_FLAG_HAS_FILTER = (1 << 0),
AD7791_FLAG_HAS_BUFFER = (1 << 1),
AD7791_FLAG_HAS_UNIPOLAR = (1 << 2),
AD7791_FLAG_HAS_BURNOUT = (1 << 3),
};
struct ad7791_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
enum ad7791_chip_info_flags flags;
};
static const struct ad7791_chip_info ad7791_chip_infos[] = {
[AD7787] = {
.channels = ad7787_channels,
.num_channels = ARRAY_SIZE(ad7787_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
},
[AD7788] = {
.channels = ad7790_channels,
.num_channels = ARRAY_SIZE(ad7790_channels),
.flags = AD7791_FLAG_HAS_UNIPOLAR,
},
[AD7789] = {
.channels = ad7791_channels,
.num_channels = ARRAY_SIZE(ad7791_channels),
.flags = AD7791_FLAG_HAS_UNIPOLAR,
},
[AD7790] = {
.channels = ad7790_channels,
.num_channels = ARRAY_SIZE(ad7790_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_BURNOUT,
},
[AD7791] = {
.channels = ad7791_channels,
.num_channels = ARRAY_SIZE(ad7791_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
},
};
struct ad7791_state {
struct ad_sigma_delta sd;
uint8_t mode;
uint8_t filter;
struct regulator *reg;
const struct ad7791_chip_info *info;
};
static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd)
{
return container_of(sd, struct ad7791_state, sd);
}
static int ad7791_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
{
ad_sd_set_comm(sd, channel);
return 0;
}
static int ad7791_set_mode(struct ad_sigma_delta *sd,
enum ad_sigma_delta_mode mode)
{
struct ad7791_state *st = ad_sigma_delta_to_ad7791(sd);
switch (mode) {
case AD_SD_MODE_CONTINUOUS:
mode = AD7791_MODE_CONTINUOUS;
break;
case AD_SD_MODE_SINGLE:
mode = AD7791_MODE_SINGLE;
break;
case AD_SD_MODE_IDLE:
case AD_SD_MODE_POWERDOWN:
mode = AD7791_MODE_POWERDOWN;
break;
}
st->mode &= ~AD7791_MODE_SEL_MASK;
st->mode |= AD7791_MODE_SEL(mode);
return ad_sd_write_reg(sd, AD7791_REG_MODE, sizeof(st->mode), st->mode);
}
static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
.set_channel = ad7791_set_channel,
.set_mode = ad7791_set_mode,
.has_registers = true,
.addr_shift = 4,
.read_mask = BIT(3),
};
static int ad7791_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct ad7791_state *st = iio_priv(indio_dev);
bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR);
switch (info) {
case IIO_CHAN_INFO_RAW:
return ad_sigma_delta_single_conversion(indio_dev, chan, val);
case IIO_CHAN_INFO_OFFSET:
/**
* Unipolar: 0 to VREF
* Bipolar -VREF to VREF
**/
if (unipolar)
*val = 0;
else
*val = -(1 << (chan->scan_type.realbits - 1));
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* The monitor channel uses an internal reference. */
if (chan->address == AD7791_CH_AVDD_MONITOR) {
/*
* The signal is attenuated by a factor of 5 and
* compared against a 1.17V internal reference.
*/
*val = 1170 * 5;
} else {
int voltage_uv;
voltage_uv = regulator_get_voltage(st->reg);
if (voltage_uv < 0)
return voltage_uv;
*val = voltage_uv / 1000;
}
if (unipolar)
*val2 = chan->scan_type.realbits;
else
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const char * const ad7791_sample_freq_avail[] = {
[AD7791_FILTER_RATE_120] = "120",
[AD7791_FILTER_RATE_100] = "100",
[AD7791_FILTER_RATE_33_3] = "33.3",
[AD7791_FILTER_RATE_20] = "20",
[AD7791_FILTER_RATE_16_6] = "16.6",
[AD7791_FILTER_RATE_16_7] = "16.7",
[AD7791_FILTER_RATE_13_3] = "13.3",
[AD7791_FILTER_RATE_9_5] = "9.5",
};
static ssize_t ad7791_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7791_state *st = iio_priv(indio_dev);
unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK;
return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]);
}
static ssize_t ad7791_write_frequency(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7791_state *st = iio_priv(indio_dev);
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) {
mutex_lock(&indio_dev->mlock);
st->filter &= ~AD7791_FILTER_RATE_MASK;
st->filter |= i;
ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
sizeof(st->filter), st->filter);
mutex_unlock(&indio_dev->mlock);
ret = 0;
break;
}
}
return ret ? ret : len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad7791_read_frequency,
ad7791_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5");
static struct attribute *ad7791_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad7791_attribute_group = {
.attrs = ad7791_attributes,
};
static const struct iio_info ad7791_info = {
.read_raw = &ad7791_read_raw,
.attrs = &ad7791_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7791_no_filter_info = {
.read_raw = &ad7791_read_raw,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static int ad7791_setup(struct ad7791_state *st,
struct ad7791_platform_data *pdata)
{
/* Set to poweron-reset default values */
st->mode = AD7791_MODE_BUFFER;
st->filter = AD7791_FILTER_RATE_16_6;
if (!pdata)
return 0;
if ((st->info->flags & AD7791_FLAG_HAS_BUFFER) && !pdata->buffered)
st->mode &= ~AD7791_MODE_BUFFER;
if ((st->info->flags & AD7791_FLAG_HAS_BURNOUT) &&
pdata->burnout_current)
st->mode |= AD7791_MODE_BURNOUT;
if ((st->info->flags & AD7791_FLAG_HAS_UNIPOLAR) && pdata->unipolar)
st->mode |= AD7791_MODE_UNIPOLAR;
return ad_sd_write_reg(&st->sd, AD7791_REG_MODE, sizeof(st->mode),
st->mode);
}
static int ad7791_probe(struct spi_device *spi)
{
struct ad7791_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad7791_state *st;
int ret;
if (!spi->irq) {
dev_err(&spi->dev, "Missing IRQ.\n");
return -ENXIO;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
if (st->info->flags & AD7791_FLAG_HAS_FILTER)
indio_dev->info = &ad7791_info;
else
indio_dev->info = &ad7791_no_filter_info;
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
if (ret)
goto error_disable_reg;
ret = ad7791_setup(st, pdata);
if (ret)
goto error_remove_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad7791_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7791_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7791_spi_ids[] = {
{ "ad7787", AD7787 },
{ "ad7788", AD7788 },
{ "ad7789", AD7789 },
{ "ad7790", AD7790 },
{ "ad7791", AD7791 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7791_spi_ids);
static struct spi_driver ad7791_driver = {
.driver = {
.name = "ad7791",
.owner = THIS_MODULE,
},
.probe = ad7791_probe,
.remove = ad7791_remove,
.id_table = ad7791_spi_ids,
};
module_spi_driver(ad7791_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver");
MODULE_LICENSE("GPL v2");

865
drivers/iio/adc/ad7793.c Normal file
View file

@ -0,0 +1,865 @@
/*
* AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver
*
* Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <linux/platform_data/ad7793.h>
/* Registers */
#define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */
#define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */
#define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */
#define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */
#define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */
#define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */
#define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */
#define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit
* (AD7792)/24-bit (AD7793)) */
#define AD7793_REG_FULLSALE 7 /* Full-Scale Register
* (RW, 16-bit (AD7792)/24-bit (AD7793)) */
/* Communications Register Bit Designations (AD7793_REG_COMM) */
#define AD7793_COMM_WEN (1 << 7) /* Write Enable */
#define AD7793_COMM_WRITE (0 << 6) /* Write Operation */
#define AD7793_COMM_READ (1 << 6) /* Read Operation */
#define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
#define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */
/* Status Register Bit Designations (AD7793_REG_STAT) */
#define AD7793_STAT_RDY (1 << 7) /* Ready */
#define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */
#define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */
#define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */
#define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */
/* Mode Register Bit Designations (AD7793_REG_MODE) */
#define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */
#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */
#define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */
#define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */
#define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */
#define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */
#define AD7793_MODE_IDLE 2 /* Idle Mode */
#define AD7793_MODE_PWRDN 3 /* Power-Down Mode */
#define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */
#define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */
#define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */
#define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */
#define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not
* available at the CLK pin */
#define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available
* at the CLK pin */
#define AD7793_CLK_EXT 2 /* External 64 kHz Clock */
#define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */
/* Configuration Register Bit Designations (AD7793_REG_CONF) */
#define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage
* Generator Enable */
#define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */
#define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */
#define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */
#define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */
#define AD7793_CONF_REFSEL(x) ((x) << 6) /* INT/EXT Reference Select */
#define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */
#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */
#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */
#define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */
#define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */
#define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */
#define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */
#define AD7793_CH_TEMP 6 /* Temp Sensor */
#define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */
#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */
#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */
#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */
#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */
/* ID Register Bit Designations (AD7793_REG_ID) */
#define AD7785_ID 0xB
#define AD7792_ID 0xA
#define AD7793_ID 0xB
#define AD7794_ID 0xF
#define AD7795_ID 0xF
#define AD7796_ID 0xA
#define AD7797_ID 0xB
#define AD7798_ID 0x8
#define AD7799_ID 0x9
#define AD7793_ID_MASK 0xF
/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */
#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1,
* IEXC2 connect to IOUT2 */
#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2,
* IEXC2 connect to IOUT1 */
#define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources
* IEXC1,2 connect to IOUT1 */
#define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources
* IEXC1,2 connect to IOUT2 */
#define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */
#define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */
#define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */
/* NOTE:
* The AD7792/AD7793 features a dual use data out ready DOUT/RDY output.
* In order to avoid contentions on the SPI bus, it's therefore necessary
* to use spi bus locking.
*
* The DOUT/RDY output must also be wired to an interrupt capable GPIO.
*/
#define AD7793_FLAG_HAS_CLKSEL BIT(0)
#define AD7793_FLAG_HAS_REFSEL BIT(1)
#define AD7793_FLAG_HAS_VBIAS BIT(2)
#define AD7793_HAS_EXITATION_CURRENT BIT(3)
#define AD7793_FLAG_HAS_GAIN BIT(4)
#define AD7793_FLAG_HAS_BUFFER BIT(5)
struct ad7793_chip_info {
unsigned int id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int flags;
const struct iio_info *iio_info;
const u16 *sample_freq_avail;
};
struct ad7793_state {
const struct ad7793_chip_info *chip_info;
struct regulator *reg;
u16 int_vref_mv;
u16 mode;
u16 conf;
u32 scale_avail[8][2];
struct ad_sigma_delta sd;
};
enum ad7793_supported_device_ids {
ID_AD7785,
ID_AD7792,
ID_AD7793,
ID_AD7794,
ID_AD7795,
ID_AD7796,
ID_AD7797,
ID_AD7798,
ID_AD7799,
};
static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd)
{
return container_of(sd, struct ad7793_state, sd);
}
static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
{
struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
st->conf &= ~AD7793_CONF_CHAN_MASK;
st->conf |= AD7793_CONF_CHAN(channel);
return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf);
}
static int ad7793_set_mode(struct ad_sigma_delta *sd,
enum ad_sigma_delta_mode mode)
{
struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
st->mode &= ~AD7793_MODE_SEL_MASK;
st->mode |= AD7793_MODE_SEL(mode);
return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode);
}
static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
.set_channel = ad7793_set_channel,
.set_mode = ad7793_set_mode,
.has_registers = true,
.addr_shift = 3,
.read_mask = BIT(6),
};
static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M},
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M},
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M}
};
static int ad7793_calibrate_all(struct ad7793_state *st)
{
return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr,
ARRAY_SIZE(ad7793_calib_arr));
}
static int ad7793_check_platform_data(struct ad7793_state *st,
const struct ad7793_platform_data *pdata)
{
if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 ||
pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) &&
((pdata->exitation_current != AD7793_IX_10uA) &&
(pdata->exitation_current != AD7793_IX_210uA)))
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL) &&
pdata->clock_src != AD7793_CLK_SRC_INT)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_REFSEL) &&
pdata->refsel != AD7793_REFSEL_REFIN1)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS) &&
pdata->bias_voltage != AD7793_BIAS_VOLTAGE_DISABLED)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) &&
pdata->exitation_current != AD7793_IX_DISABLED)
return -EINVAL;
return 0;
}
static int ad7793_setup(struct iio_dev *indio_dev,
const struct ad7793_platform_data *pdata,
unsigned int vref_mv)
{
struct ad7793_state *st = iio_priv(indio_dev);
int i, ret = -1;
unsigned long long scale_uv;
u32 id;
ret = ad7793_check_platform_data(st, pdata);
if (ret)
return ret;
/* reset the serial interface */
ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret));
if (ret < 0)
goto out;
usleep_range(500, 2000); /* Wait for at least 500us */
/* write/read test for device presence */
ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id);
if (ret)
goto out;
id &= AD7793_ID_MASK;
if (id != st->chip_info->id) {
dev_err(&st->sd.spi->dev, "device ID query failed\n");
goto out;
}
st->mode = AD7793_MODE_RATE(1);
st->conf = 0;
if (st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL)
st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src);
if (st->chip_info->flags & AD7793_FLAG_HAS_REFSEL)
st->conf |= AD7793_CONF_REFSEL(pdata->refsel);
if (st->chip_info->flags & AD7793_FLAG_HAS_VBIAS)
st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage);
if (pdata->buffered || !(st->chip_info->flags & AD7793_FLAG_HAS_BUFFER))
st->conf |= AD7793_CONF_BUF;
if (pdata->boost_enable &&
(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS))
st->conf |= AD7793_CONF_BOOST;
if (pdata->burnout_current)
st->conf |= AD7793_CONF_BO_EN;
if (pdata->unipolar)
st->conf |= AD7793_CONF_UNIPOLAR;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_GAIN))
st->conf |= AD7793_CONF_GAIN(7);
ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE);
if (ret)
goto out;
ret = ad7793_set_channel(&st->sd, 0);
if (ret)
goto out;
if (st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) {
ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1,
pdata->exitation_current |
(pdata->current_source_direction << 2));
if (ret)
goto out;
}
ret = ad7793_calibrate_all(st);
if (ret)
goto out;
/* Populate available ADC input ranges */
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
scale_uv = ((u64)vref_mv * 100000000)
>> (st->chip_info->channels[0].scan_type.realbits -
(!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1));
scale_uv >>= i;
st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
st->scale_avail[i][0] = scale_uv;
}
return 0;
out:
dev_err(&st->sd.spi->dev, "setup failed\n");
return ret;
}
static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39,
33, 19, 17, 16, 12, 10, 8, 6, 4};
static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0,
33, 0, 17, 16, 12, 10, 8, 6, 4};
static ssize_t ad7793_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]);
}
static ssize_t ad7793_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
long lval;
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = kstrtol(buf, 10, &lval);
if (ret)
return ret;
if (lval == 0)
return -EINVAL;
ret = -EINVAL;
for (i = 0; i < 16; i++)
if (lval == st->chip_info->sample_freq_avail[i]) {
mutex_lock(&indio_dev->mlock);
st->mode &= ~AD7793_MODE_RATE(-1);
st->mode |= AD7793_MODE_RATE(i);
ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
sizeof(st->mode), st->mode);
mutex_unlock(&indio_dev->mlock);
ret = 0;
}
return ret ? ret : len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad7793_read_frequency,
ad7793_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"470 242 123 62 50 39 33 19 17 16 12 10 8 6 4");
static IIO_CONST_ATTR_NAMED(sampling_frequency_available_ad7797,
sampling_frequency_available, "123 62 50 33 17 16 12 10 8 6 4");
static ssize_t ad7793_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0],
st->scale_avail[i][1]);
len += sprintf(buf + len, "\n");
return len;
}
static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available,
in_voltage-voltage_scale_available, S_IRUGO,
ad7793_show_scale_available, NULL, 0);
static struct attribute *ad7793_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_m_in_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad7793_attribute_group = {
.attrs = ad7793_attributes,
};
static struct attribute *ad7797_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr,
NULL
};
static const struct attribute_group ad7797_attribute_group = {
.attrs = ad7797_attributes,
};
static int ad7793_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad7793_state *st = iio_priv(indio_dev);
int ret;
unsigned long long scale_uv;
bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad_sigma_delta_single_conversion(indio_dev, chan, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
if (chan->differential) {
*val = st->
scale_avail[(st->conf >> 8) & 0x7][0];
*val2 = st->
scale_avail[(st->conf >> 8) & 0x7][1];
return IIO_VAL_INT_PLUS_NANO;
} else {
/* 1170mV / 2^23 * 6 */
scale_uv = (1170ULL * 1000000000ULL * 6ULL);
}
break;
case IIO_TEMP:
/* 1170mV / 0.81 mV/C / 2^23 */
scale_uv = 1444444444444444ULL;
break;
default:
return -EINVAL;
}
scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1));
*val = 0;
*val2 = scale_uv;
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_OFFSET:
if (!unipolar)
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
/* Kelvin to Celsius */
if (chan->type == IIO_TEMP) {
unsigned long long offset;
unsigned int shift;
shift = chan->scan_type.realbits - (unipolar ? 0 : 1);
offset = 273ULL << shift;
do_div(offset, 1444);
*val -= offset;
}
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad7793_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad7793_state *st = iio_priv(indio_dev);
int ret, i;
unsigned int tmp;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
tmp = st->conf;
st->conf &= ~AD7793_CONF_GAIN(-1);
st->conf |= AD7793_CONF_GAIN(i);
if (tmp == st->conf)
break;
ad_sd_write_reg(&st->sd, AD7793_REG_CONF,
sizeof(st->conf), st->conf);
ad7793_calibrate_all(st);
break;
}
break;
default:
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
return IIO_VAL_INT_PLUS_NANO;
}
static const struct iio_info ad7793_info = {
.read_raw = &ad7793_read_raw,
.write_raw = &ad7793_write_raw,
.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
.attrs = &ad7793_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7797_info = {
.read_raw = &ad7793_read_raw,
.write_raw = &ad7793_write_raw,
.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
.attrs = &ad7793_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \
AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \
AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \
AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \
IIO_CHAN_SOFT_TIMESTAMP(6), \
}
#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(9), \
}
#define DECLARE_AD7797_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7799_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4);
static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0);
static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0);
static DECLARE_AD7795_CHANNELS(ad7794, 16, 32);
static DECLARE_AD7795_CHANNELS(ad7795, 24, 32);
static DECLARE_AD7797_CHANNELS(ad7796, 16, 16);
static DECLARE_AD7797_CHANNELS(ad7797, 24, 32);
static DECLARE_AD7799_CHANNELS(ad7798, 16, 16);
static DECLARE_AD7799_CHANNELS(ad7799, 24, 32);
static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
[ID_AD7785] = {
.id = AD7785_ID,
.channels = ad7785_channels,
.num_channels = ARRAY_SIZE(ad7785_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7792] = {
.id = AD7792_ID,
.channels = ad7792_channels,
.num_channels = ARRAY_SIZE(ad7792_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7793] = {
.id = AD7793_ID,
.channels = ad7793_channels,
.num_channels = ARRAY_SIZE(ad7793_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7794] = {
.id = AD7794_ID,
.channels = ad7794_channels,
.num_channels = ARRAY_SIZE(ad7794_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7795] = {
.id = AD7795_ID,
.channels = ad7795_channels,
.num_channels = ARRAY_SIZE(ad7795_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7796] = {
.id = AD7796_ID,
.channels = ad7796_channels,
.num_channels = ARRAY_SIZE(ad7796_channels),
.iio_info = &ad7797_info,
.sample_freq_avail = ad7797_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL,
},
[ID_AD7797] = {
.id = AD7797_ID,
.channels = ad7797_channels,
.num_channels = ARRAY_SIZE(ad7797_channels),
.iio_info = &ad7797_info,
.sample_freq_avail = ad7797_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL,
},
[ID_AD7798] = {
.id = AD7798_ID,
.channels = ad7798_channels,
.num_channels = ARRAY_SIZE(ad7798_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7799] = {
.id = AD7799_ID,
.channels = ad7799_channels,
.num_channels = ARRAY_SIZE(ad7799_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
};
static int ad7793_probe(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
struct ad7793_state *st;
struct iio_dev *indio_dev;
int ret, vref_mv = 0;
if (!pdata) {
dev_err(&spi->dev, "no platform data?\n");
return -ENODEV;
}
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
st->reg = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
vref_mv = regulator_get_voltage(st->reg);
if (vref_mv < 0) {
ret = vref_mv;
goto error_disable_reg;
}
vref_mv /= 1000;
} else {
vref_mv = 1170; /* Build-in ref */
}
st->chip_info =
&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->iio_info;
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
if (ret)
goto error_disable_reg;
ret = ad7793_setup(indio_dev, pdata, vref_mv);
if (ret)
goto error_remove_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_reg:
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_disable(st->reg);
return ret;
}
static int ad7793_remove(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7793_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7793_id[] = {
{"ad7785", ID_AD7785},
{"ad7792", ID_AD7792},
{"ad7793", ID_AD7793},
{"ad7794", ID_AD7794},
{"ad7795", ID_AD7795},
{"ad7796", ID_AD7796},
{"ad7797", ID_AD7797},
{"ad7798", ID_AD7798},
{"ad7799", ID_AD7799},
{}
};
MODULE_DEVICE_TABLE(spi, ad7793_id);
static struct spi_driver ad7793_driver = {
.driver = {
.name = "ad7793",
.owner = THIS_MODULE,
},
.probe = ad7793_probe,
.remove = ad7793_remove,
.id_table = ad7793_id,
};
module_spi_driver(ad7793_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs");
MODULE_LICENSE("GPL v2");

369
drivers/iio/adc/ad7887.c Normal file
View file

@ -0,0 +1,369 @@
/*
* AD7887 SPI ADC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/platform_data/ad7887.h>
#define AD7887_REF_DIS BIT(5) /* on-chip reference disable */
#define AD7887_DUAL BIT(4) /* dual-channel mode */
#define AD7887_CH_AIN1 BIT(3) /* convert on channel 1, DUAL=1 */
#define AD7887_CH_AIN0 0 /* convert on channel 0, DUAL=0,1 */
#define AD7887_PM_MODE1 0 /* CS based shutdown */
#define AD7887_PM_MODE2 1 /* full on */
#define AD7887_PM_MODE3 2 /* auto shutdown after conversion */
#define AD7887_PM_MODE4 3 /* standby mode */
enum ad7887_channels {
AD7887_CH0,
AD7887_CH0_CH1,
AD7887_CH1,
};
/**
* struct ad7887_chip_info - chip specifc information
* @int_vref_mv: the internal reference voltage
* @channel: channel specification
*/
struct ad7887_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[3];
};
struct ad7887_state {
struct spi_device *spi;
const struct ad7887_chip_info *chip_info;
struct regulator *reg;
struct spi_transfer xfer[4];
struct spi_message msg[3];
struct spi_message *ring_msg;
unsigned char tx_cmd_buf[4];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* Buffer needs to be large enough to hold two 16 bit samples and a
* 64 bit aligned 64 bit timestamp.
*/
unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)]
____cacheline_aligned;
};
enum ad7887_supported_device_ids {
ID_AD7887
};
static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
/* We know this is a single long so can 'cheat' */
switch (*indio_dev->active_scan_mask) {
case (1 << 0):
st->ring_msg = &st->msg[AD7887_CH0];
break;
case (1 << 1):
st->ring_msg = &st->msg[AD7887_CH1];
/* Dummy read: push CH1 setting down to hardware */
spi_sync(st->spi, st->ring_msg);
break;
case ((1 << 1) | (1 << 0)):
st->ring_msg = &st->msg[AD7887_CH0_CH1];
break;
}
return 0;
}
static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
/* dummy read: restore default CH0 settin */
return spi_sync(st->spi, &st->msg[AD7887_CH0]);
}
/**
* ad7887_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7887_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7887_state *st = iio_priv(indio_dev);
int b_sent;
b_sent = spi_sync(st->spi, st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
.preenable = &ad7887_ring_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad7887_ring_postdisable,
};
static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch)
{
int ret = spi_sync(st->spi, &st->msg[ch]);
if (ret)
return ret;
return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1];
}
static int ad7887_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7887_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7887_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = ret >> chan->scan_type.shift;
*val &= GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (st->reg) {
*val = regulator_get_voltage(st->reg);
if (*val < 0)
return *val;
*val /= 1000;
} else {
*val = st->chip_info->int_vref_mv;
}
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
/*
* More devices added in future
*/
[ID_AD7887] = {
.channel[0] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1,
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[1] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2),
.int_vref_mv = 2500,
},
};
static const struct iio_info ad7887_info = {
.read_raw = &ad7887_read_raw,
.driver_module = THIS_MODULE,
};
static int ad7887_probe(struct spi_device *spi)
{
struct ad7887_platform_data *pdata = spi->dev.platform_data;
struct ad7887_state *st;
struct iio_dev *indio_dev;
uint8_t mode;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (!pdata || !pdata->use_onchip_ref) {
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
st->chip_info =
&ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
/* Estabilish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad7887_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Setup default message */
mode = AD7887_PM_MODE4;
if (!pdata || !pdata->use_onchip_ref)
mode |= AD7887_REF_DIS;
if (pdata && pdata->en_dual)
mode |= AD7887_DUAL;
st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode;
st->xfer[0].rx_buf = &st->data[0];
st->xfer[0].tx_buf = &st->tx_cmd_buf[0];
st->xfer[0].len = 2;
spi_message_init(&st->msg[AD7887_CH0]);
spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]);
if (pdata && pdata->en_dual) {
st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode;
st->xfer[1].rx_buf = &st->data[0];
st->xfer[1].tx_buf = &st->tx_cmd_buf[2];
st->xfer[1].len = 2;
st->xfer[2].rx_buf = &st->data[2];
st->xfer[2].tx_buf = &st->tx_cmd_buf[0];
st->xfer[2].len = 2;
spi_message_init(&st->msg[AD7887_CH0_CH1]);
spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]);
spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]);
st->xfer[3].rx_buf = &st->data[2];
st->xfer[3].tx_buf = &st->tx_cmd_buf[2];
st->xfer[3].len = 2;
spi_message_init(&st->msg[AD7887_CH1]);
spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = 3;
} else {
indio_dev->channels = &st->chip_info->channel[1];
indio_dev->num_channels = 2;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7887_trigger_handler, &ad7887_ring_setup_ops);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unregister_ring;
return 0;
error_unregister_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (st->reg)
regulator_disable(st->reg);
return ret;
}
static int ad7887_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7887_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (st->reg)
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7887_id[] = {
{"ad7887", ID_AD7887},
{}
};
MODULE_DEVICE_TABLE(spi, ad7887_id);
static struct spi_driver ad7887_driver = {
.driver = {
.name = "ad7887",
.owner = THIS_MODULE,
},
.probe = ad7887_probe,
.remove = ad7887_remove,
.id_table = ad7887_id,
};
module_spi_driver(ad7887_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
MODULE_LICENSE("GPL v2");

371
drivers/iio/adc/ad7923.c Normal file
View file

@ -0,0 +1,371 @@
/*
* AD7904/AD7914/AD7923/AD7924 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define AD7923_WRITE_CR (1 << 11) /* write control register */
#define AD7923_RANGE (1 << 1) /* range to REFin */
#define AD7923_CODING (1 << 0) /* coding is straight binary */
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
#define AD7923_CHANNEL_0 (0) /* analog input 0 */
#define AD7923_CHANNEL_1 (1) /* analog input 1 */
#define AD7923_CHANNEL_2 (2) /* analog input 2 */
#define AD7923_CHANNEL_3 (3) /* analog input 3 */
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
#define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */
#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \
+ ((sequence & 2) << 9))
/* write sequence fonction */
/* left shift for CR : bit 11 transmit in first */
#define AD7923_SHIFT_REGISTER 4
/* val = value, dec = left shift, bits = number of bits of the mask */
#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1))
struct ad7923_state {
struct spi_device *spi;
struct spi_transfer ring_xfer[5];
struct spi_transfer scan_single_xfer[2];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
struct regulator *reg;
unsigned int settings;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 rx_buf[4] ____cacheline_aligned;
__be16 tx_buf[4];
};
struct ad7923_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
enum ad7923_id {
AD7904,
AD7914,
AD7924,
};
#define AD7923_V_CHAN(index, bits) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define DECLARE_AD7923_CHANNELS(name, bits) \
const struct iio_chan_spec name ## _channels[] = { \
AD7923_V_CHAN(0, bits), \
AD7923_V_CHAN(1, bits), \
AD7923_V_CHAN(2, bits), \
AD7923_V_CHAN(3, bits), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
static DECLARE_AD7923_CHANNELS(ad7904, 8);
static DECLARE_AD7923_CHANNELS(ad7914, 10);
static DECLARE_AD7923_CHANNELS(ad7924, 12);
static const struct ad7923_chip_info ad7923_chip_info[] = {
[AD7904] = {
.channels = ad7904_channels,
.num_channels = ARRAY_SIZE(ad7904_channels),
},
[AD7914] = {
.channels = ad7914_channels,
.num_channels = ARRAY_SIZE(ad7914_channels),
},
[AD7924] = {
.channels = ad7924_channels,
.num_channels = ARRAY_SIZE(ad7924_channels),
},
};
/**
* ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7923_state *st = iio_priv(indio_dev);
int i, cmd, len;
len = 0;
for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[len++] = cpu_to_be16(cmd);
}
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = len;
st->ring_xfer[0].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
for (i = 0; i < len; i++) {
st->ring_xfer[i + 1].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 1].len = 2;
st->ring_xfer[i + 1].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 1], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7923_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7923_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7923_state *st = iio_priv(indio_dev);
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
{
int ret, cmd;
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(ch) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[0] = cpu_to_be16(cmd);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
return be16_to_cpu(st->rx_buf[0]);
}
static int ad7923_get_range(struct ad7923_state *st)
{
int vref;
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
vref /= 1000;
if (!(st->settings & AD7923_RANGE))
vref *= 2;
return vref;
}
static int ad7923_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7923_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7923_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
if (chan->address == EXTRACT(ret, 12, 4))
*val = EXTRACT(ret, 0, 12);
else
return -EIO;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = ad7923_get_range(st);
if (ret < 0)
return ret;
*val = ret;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info ad7923_info = {
.read_raw = &ad7923_read_raw,
.update_scan_mode = ad7923_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int ad7923_probe(struct spi_device *spi)
{
struct ad7923_state *st;
struct iio_dev *indio_dev;
const struct ad7923_chip_info *info;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->settings = AD7923_CODING | AD7923_RANGE |
AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS);
info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data];
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->channels;
indio_dev->num_channels = info->num_channels;
indio_dev->info = &ad7923_info;
/* Setup default message */
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[1].len = 2;
spi_message_init(&st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
st->reg = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7923_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad7923_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7923_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7923_id[] = {
{"ad7904", AD7904},
{"ad7914", AD7914},
{"ad7923", AD7924},
{"ad7924", AD7924},
{}
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
static struct spi_driver ad7923_driver = {
.driver = {
.name = "ad7923",
.owner = THIS_MODULE,
},
.probe = ad7923_probe,
.remove = ad7923_remove,
.id_table = ad7923_id,
};
module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_LICENSE("GPL v2");

905
drivers/iio/adc/ad799x.c Normal file
View file

@ -0,0 +1,905 @@
/*
* iio/adc/ad799x.c
* Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc.
*
* based on iio/adc/max1363
* Copyright (C) 2008-2010 Jonathan Cameron
*
* based on linux/drivers/i2c/chips/max123x
* Copyright (C) 2002-2004 Stefan Eletzhofer
*
* based on linux/drivers/acron/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ad799x.c
*
* Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997,
* ad7998 and similar chips.
*
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.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 BIT(3)
#define AD7998_ALERT_EN BIT(2)
#define AD7998_BUSY_ALERT BIT(1)
#define AD7998_BUSY_ALERT_POL BIT(0)
#define AD7998_CONV_RES_REG 0x0
#define AD7998_ALERT_STAT_REG 0x1
#define AD7998_CONF_REG 0x2
#define AD7998_CYCLE_TMR_REG 0x3
#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4)
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
#define AD7998_CYC_MASK GENMASK(2, 0)
#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 BIT(7)
#define AD7997_8_READ_SEQUENCE (BIT(6) | BIT(5) | BIT(4))
enum {
ad7991,
ad7995,
ad7999,
ad7992,
ad7993,
ad7994,
ad7997,
ad7998
};
/**
* struct ad799x_chip_config - chip specific information
* @channel: channel specification
* @default_config: device default configuration
* @info: pointer to iio_info struct
*/
struct ad799x_chip_config {
const struct iio_chan_spec channel[9];
u16 default_config;
const struct iio_info *info;
};
/**
* struct ad799x_chip_info - chip specific information
* @num_channels: number of channels
* @noirq_config: device configuration w/o IRQ
* @irq_config: device configuration w/IRQ
*/
struct ad799x_chip_info {
int num_channels;
const struct ad799x_chip_config noirq_config;
const struct ad799x_chip_config irq_config;
};
struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_config *chip_config;
struct regulator *reg;
struct regulator *vref;
unsigned id;
u16 config;
u8 *rx_buf;
unsigned int transfer_size;
};
static int ad799x_write_config(struct ad799x_state *st, u16 val)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
val);
case ad7992:
case ad7993:
case ad7994:
return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
val);
default:
/* Will be written when doing a conversion */
st->config = val;
return 0;
}
}
static int ad799x_read_config(struct ad799x_state *st)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
case ad7992:
case ad7993:
case ad7994:
return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
default:
/* No readback support */
return st->config;
}
}
/**
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad799x_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad799x_state *st = iio_priv(indio_dev);
int b_sent;
u8 cmd;
switch (st->id) {
case ad7991:
case ad7995:
case ad7999:
cmd = st->config |
(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT);
break;
case ad7992:
case ad7993:
case ad7994:
cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) |
AD7998_CONV_RES_REG;
break;
case ad7997:
case ad7998:
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
break;
default:
cmd = 0;
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
cmd, st->transfer_size, st->rx_buf);
if (b_sent < 0)
goto out;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad799x_state *st = iio_priv(indio_dev);
kfree(st->rx_buf);
st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (!st->rx_buf)
return -ENOMEM;
st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
switch (st->id) {
case ad7992:
case ad7993:
case ad7994:
case ad7997:
case ad7998:
st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT);
st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT);
return ad799x_write_config(st, st->config);
default:
return 0;
}
}
static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
{
u8 cmd;
switch (st->id) {
case ad7991:
case ad7995:
case ad7999:
cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT);
break;
case ad7992:
case ad7993:
case ad7994:
cmd = BIT(ch) << AD799X_CHANNEL_SHIFT;
break;
case ad7997:
case ad7998:
cmd = (ch << AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE;
break;
default:
return -EINVAL;
}
return i2c_smbus_read_word_swapped(st->client, cmd);
}
static int ad799x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad799x_scan_direct(st, chan->scan_index);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(st->vref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const unsigned int ad7998_frequencies[] = {
[AD7998_CYC_DIS] = 0,
[AD7998_CYC_TCONF_32] = 15625,
[AD7998_CYC_TCONF_64] = 7812,
[AD7998_CYC_TCONF_128] = 3906,
[AD7998_CYC_TCONF_512] = 976,
[AD7998_CYC_TCONF_1024] = 488,
[AD7998_CYC_TCONF_2048] = 244,
};
static ssize_t ad799x_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]);
}
static ssize_t ad799x_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
long val;
int ret, i;
ret = kstrtol(buf, 10, &val);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
goto error_ret_mutex;
/* Wipe the bits clean */
ret &= ~AD7998_CYC_MASK;
for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++)
if (val == ad7998_frequencies[i])
break;
if (i == ARRAY_SIZE(ad7998_frequencies)) {
ret = -EINVAL;
goto error_ret_mutex;
}
ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
ret | i);
if (ret < 0)
goto error_ret_mutex;
ret = len;
error_ret_mutex:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad799x_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad799x_state *st = iio_priv(indio_dev);
if (!(st->config & AD7998_ALERT_EN))
return 0;
if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index))
return 1;
return 0;
}
static int ad799x_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto done;
}
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
else
st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT);
if (st->config >> AD799X_CHANNEL_SHIFT)
st->config |= AD7998_ALERT_EN;
else
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
done:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
enum iio_event_direction dir,
enum iio_event_info info)
{
switch (info) {
case IIO_EV_INFO_VALUE:
if (dir == IIO_EV_DIR_FALLING)
return AD7998_DATALOW_REG(chan->channel);
else
return AD7998_DATAHIGH_REG(chan->channel);
case IIO_EV_INFO_HYSTERESIS:
return AD7998_HYST_REG(chan->channel);
default:
return -EINVAL;
}
return 0;
}
static int ad799x_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_write_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info),
val << chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad799x_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info));
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1 , 0);
return IIO_VAL_INT;
}
static irqreturn_t ad799x_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad799x_state *st = iio_priv(private);
int i, ret;
ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG);
if (ret <= 0)
goto done;
if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
AD7998_ALERT_STAT_CLEAR) < 0)
goto done;
for (i = 0; i < 8; i++) {
if (ret & BIT(i))
iio_push_event(indio_dev,
i & 0x1 ?
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) :
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns());
}
done:
return IRQ_HANDLED;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad799x_read_frequency,
ad799x_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0");
static struct attribute *ad799x_event_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes,
.name = "events",
};
static const struct iio_info ad7991_info = {
.read_raw = &ad799x_read_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7993_4_7_8_noirq_info = {
.read_raw = &ad799x_read_raw,
.driver_module = THIS_MODULE,
.update_scan_mode = ad799x_update_scan_mode,
};
static const struct iio_info ad7993_4_7_8_irq_info = {
.read_raw = &ad799x_read_raw,
.event_attrs = &ad799x_event_attrs_group,
.read_event_config = &ad799x_read_event_config,
.write_event_config = &ad799x_write_event_config,
.read_event_value = &ad799x_read_event_value,
.write_event_value = &ad799x_write_event_value,
.driver_module = THIS_MODULE,
.update_scan_mode = ad799x_update_scan_mode,
};
static const struct iio_event_spec ad799x_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = (_realbits), \
.storagebits = 16, \
.shift = 12 - (_realbits), \
.endianness = IIO_BE, \
}, \
.event_spec = _ev_spec, \
.num_event_specs = _num_ev_spec, \
}
#define AD799X_CHANNEL(_index, _realbits) \
_AD799X_CHANNEL(_index, _realbits, NULL, 0)
#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \
_AD799X_CHANNEL(_index, _realbits, ad799x_events, \
ARRAY_SIZE(ad799x_events))
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
[ad7991] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7995] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7999] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 8),
AD799X_CHANNEL(1, 8),
AD799X_CHANNEL(2, 8),
AD799X_CHANNEL(3, 8),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7992] = {
.num_channels = 3,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7993] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10),
AD799X_CHANNEL_WITH_EVENTS(2, 10),
AD799X_CHANNEL_WITH_EVENTS(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7994] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
AD799X_CHANNEL_WITH_EVENTS(2, 12),
AD799X_CHANNEL_WITH_EVENTS(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7997] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
AD799X_CHANNEL(4, 10),
AD799X_CHANNEL(5, 10),
AD799X_CHANNEL(6, 10),
AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10),
AD799X_CHANNEL_WITH_EVENTS(2, 10),
AD799X_CHANNEL_WITH_EVENTS(3, 10),
AD799X_CHANNEL(4, 10),
AD799X_CHANNEL(5, 10),
AD799X_CHANNEL(6, 10),
AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7998] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
AD799X_CHANNEL(4, 12),
AD799X_CHANNEL(5, 12),
AD799X_CHANNEL(6, 12),
AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
AD799X_CHANNEL_WITH_EVENTS(2, 12),
AD799X_CHANNEL_WITH_EVENTS(3, 12),
AD799X_CHANNEL(4, 12),
AD799X_CHANNEL(5, 12),
AD799X_CHANNEL(6, 12),
AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
};
static int ad799x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct ad799x_state *st;
struct iio_dev *indio_dev;
const struct ad799x_chip_info *chip_info =
&ad799x_chip_info_tbl[id->driver_data];
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
st->id = id->driver_data;
if (client->irq > 0 && chip_info->irq_config.info)
st->chip_config = &chip_info->irq_config;
else
st->chip_config = &chip_info->noirq_config;
/* TODO: Add pdata options for filtering and bit delay */
st->reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
st->vref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(st->vref)) {
ret = PTR_ERR(st->vref);
goto error_disable_reg;
}
ret = regulator_enable(st->vref);
if (ret)
goto error_disable_reg;
st->client = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->info = st->chip_config->info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = chip_info->num_channels;
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
goto error_disable_reg;
ret = ad799x_read_config(st);
if (ret < 0)
goto error_disable_reg;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad799x_trigger_handler, NULL);
if (ret)
goto error_disable_vref;
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
ad799x_event_handler,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
client->name,
indio_dev);
if (ret)
goto error_cleanup_ring;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_vref:
regulator_disable(st->vref);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad799x_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ad799x_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->vref);
regulator_disable(st->reg);
kfree(st->rx_buf);
return 0;
}
static const struct i2c_device_id ad799x_id[] = {
{ "ad7991", ad7991 },
{ "ad7995", ad7995 },
{ "ad7999", ad7999 },
{ "ad7992", ad7992 },
{ "ad7993", ad7993 },
{ "ad7994", ad7994 },
{ "ad7997", ad7997 },
{ "ad7998", ad7998 },
{}
};
MODULE_DEVICE_TABLE(i2c, ad799x_id);
static struct i2c_driver ad799x_driver = {
.driver = {
.name = "ad799x",
},
.probe = ad799x_probe,
.remove = ad799x_remove,
.id_table = ad799x_id,
};
module_i2c_driver(ad799x_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD799x ADC");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,553 @@
/*
* Support code for Analog Devices Sigma-Delta ADCs
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <asm/unaligned.h>
#define AD_SD_COMM_CHAN_MASK 0x3
#define AD_SD_REG_COMM 0x00
#define AD_SD_REG_DATA 0x03
/**
* ad_sd_set_comm() - Set communications register
*
* @sigma_delta: The sigma delta device
* @comm: New value for the communications register
*/
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
{
/* Some variants use the lower two bits of the communications register
* to select the channel */
sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
}
EXPORT_SYMBOL_GPL(ad_sd_set_comm);
/**
* ad_sd_write_reg() - Write a register
*
* @sigma_delta: The sigma delta device
* @reg: Address of the register
* @size: Size of the register (0-3)
* @val: Value to write to the register
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
unsigned int size, unsigned int val)
{
uint8_t *data = sigma_delta->data;
struct spi_transfer t = {
.tx_buf = data,
.len = size + 1,
.cs_change = sigma_delta->bus_locked,
};
struct spi_message m;
int ret;
data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm;
switch (size) {
case 3:
data[1] = val >> 16;
data[2] = val >> 8;
data[3] = val;
break;
case 2:
put_unaligned_be16(val, &data[1]);
break;
case 1:
data[1] = val;
break;
case 0:
break;
default:
return -EINVAL;
}
spi_message_init(&m);
spi_message_add_tail(&t, &m);
if (sigma_delta->bus_locked)
ret = spi_sync_locked(sigma_delta->spi, &m);
else
ret = spi_sync(sigma_delta->spi, &m);
return ret;
}
EXPORT_SYMBOL_GPL(ad_sd_write_reg);
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
unsigned int reg, unsigned int size, uint8_t *val)
{
uint8_t *data = sigma_delta->data;
int ret;
struct spi_transfer t[] = {
{
.tx_buf = data,
.len = 1,
}, {
.rx_buf = val,
.len = size,
.cs_change = sigma_delta->bus_locked,
},
};
struct spi_message m;
spi_message_init(&m);
if (sigma_delta->info->has_registers) {
data[0] = reg << sigma_delta->info->addr_shift;
data[0] |= sigma_delta->info->read_mask;
spi_message_add_tail(&t[0], &m);
}
spi_message_add_tail(&t[1], &m);
if (sigma_delta->bus_locked)
ret = spi_sync_locked(sigma_delta->spi, &m);
else
ret = spi_sync(sigma_delta->spi, &m);
return ret;
}
/**
* ad_sd_read_reg() - Read a register
*
* @sigma_delta: The sigma delta device
* @reg: Address of the register
* @size: Size of the register (1-4)
* @val: Read value
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
unsigned int reg, unsigned int size, unsigned int *val)
{
int ret;
ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data);
if (ret < 0)
goto out;
switch (size) {
case 4:
*val = get_unaligned_be32(sigma_delta->data);
break;
case 3:
*val = (sigma_delta->data[0] << 16) |
(sigma_delta->data[1] << 8) |
sigma_delta->data[2];
break;
case 2:
*val = get_unaligned_be16(sigma_delta->data);
break;
case 1:
*val = sigma_delta->data[0];
break;
default:
ret = -EINVAL;
break;
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(ad_sd_read_reg);
static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
int ret;
ret = ad_sigma_delta_set_channel(sigma_delta, channel);
if (ret)
return ret;
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
reinit_completion(&sigma_delta->completion);
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
if (ret < 0)
goto out;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ);
if (ret == 0) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
ret = -EIO;
} else {
ret = 0;
}
out:
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
return ret;
}
/**
* ad_sd_calibrate_all() - Performs channel calibration
* @sigma_delta: The sigma delta device
* @cb: Array of channels and calibration type to perform
* @n: Number of items in cb
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
const struct ad_sd_calib_data *cb, unsigned int n)
{
unsigned int i;
int ret;
for (i = 0; i < n; i++) {
ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_calibrate_all);
/**
* ad_sigma_delta_single_conversion() - Performs a single data conversion
* @indio_dev: The IIO device
* @chan: The conversion is done for this channel
* @val: Pointer to the location where to store the read value
*
* Returns: 0 on success, an error value otherwise.
*/
int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int sample, raw_sample;
int ret = 0;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
mutex_lock(&indio_dev->mlock);
ad_sigma_delta_set_channel(sigma_delta, chan->address);
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
reinit_completion(&sigma_delta->completion);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
ret = wait_for_completion_interruptible_timeout(
&sigma_delta->completion, HZ);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
if (ret == 0)
ret = -EIO;
if (ret < 0)
goto out;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
&raw_sample);
out:
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->spi->irq);
sigma_delta->irq_dis = true;
}
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
sample = raw_sample >> chan->scan_type.shift;
sample &= (1 << chan->scan_type.realbits) - 1;
*val = sample;
ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample);
if (ret)
return ret;
return IIO_VAL_INT;
}
EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion);
static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int channel;
int ret;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret < 0)
return ret;
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
ret = ad_sigma_delta_set_channel(sigma_delta,
indio_dev->channels[channel].address);
if (ret)
goto err_predisable;
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
if (ret)
goto err_unlock;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
return 0;
err_unlock:
spi_bus_unlock(sigma_delta->spi->master);
err_predisable:
return ret;
}
static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
reinit_completion(&sigma_delta->completion);
wait_for_completion_timeout(&sigma_delta->completion, HZ);
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->spi->irq);
sigma_delta->irq_dis = true;
}
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
return spi_bus_unlock(sigma_delta->spi->master);
}
static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int reg_size;
uint8_t data[16];
int ret;
memset(data, 0x00, 16);
reg_size = indio_dev->channels[0].scan_type.realbits +
indio_dev->channels[0].scan_type.shift;
reg_size = DIV_ROUND_UP(reg_size, 8);
switch (reg_size) {
case 4:
case 2:
case 1:
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[0]);
break;
case 3:
/* We store 24 bit samples in a 32 bit word. Keep the upper
* byte set to zero. */
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[1]);
break;
}
iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
return IRQ_HANDLED;
}
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
.postenable = &ad_sd_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad_sd_buffer_postdisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
{
struct ad_sigma_delta *sigma_delta = private;
complete(&sigma_delta->completion);
disable_irq_nosync(irq);
sigma_delta->irq_dis = true;
iio_trigger_poll(sigma_delta->trig);
return IRQ_HANDLED;
}
/**
* ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices
* @indio_dev: The IIO device
* @trig: The new trigger
*
* Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta
* device, -EINVAL otherwise.
*/
int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
if (sigma_delta->trig != trig)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
static const struct iio_trigger_ops ad_sd_trigger_ops = {
.owner = THIS_MODULE,
};
static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
int ret;
sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
indio_dev->id);
if (sigma_delta->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
sigma_delta->trig->ops = &ad_sd_trigger_ops;
init_completion(&sigma_delta->completion);
ret = request_irq(sigma_delta->spi->irq,
ad_sd_data_rdy_trig_poll,
IRQF_TRIGGER_LOW,
indio_dev->name,
sigma_delta);
if (ret)
goto error_free_trig;
if (!sigma_delta->irq_dis) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
}
sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
ret = iio_trigger_register(sigma_delta->trig);
if (ret)
goto error_free_irq;
/* select default trigger */
indio_dev->trig = iio_trigger_get(sigma_delta->trig);
return 0;
error_free_irq:
free_irq(sigma_delta->spi->irq, sigma_delta);
error_free_trig:
iio_trigger_free(sigma_delta->trig);
error_ret:
return ret;
}
static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
iio_trigger_unregister(sigma_delta->trig);
free_irq(sigma_delta->spi->irq, sigma_delta);
iio_trigger_free(sigma_delta->trig);
}
/**
* ad_sd_setup_buffer_and_trigger() -
* @indio_dev: The IIO device
*/
int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
{
int ret;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
if (ret)
return ret;
ret = ad_sd_probe_trigger(indio_dev);
if (ret) {
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
/**
* ad_sd_cleanup_buffer_and_trigger() -
* @indio_dev: The IIO device
*/
void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
{
ad_sd_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
/**
* ad_sd_init() - Initializes a ad_sigma_delta struct
* @sigma_delta: The ad_sigma_delta device
* @indio_dev: The IIO device which the Sigma Delta device is used for
* @spi: The SPI device for the ad_sigma_delta device
* @info: Device specific callbacks and options
*
* This function needs to be called before any other operations are performed on
* the ad_sigma_delta struct.
*/
int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
struct spi_device *spi, const struct ad_sigma_delta_info *info)
{
sigma_delta->spi = spi;
sigma_delta->info = info;
iio_device_set_drvdata(indio_dev, sigma_delta);
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_init);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
MODULE_LICENSE("GPL v2");

1439
drivers/iio/adc/at91_adc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,889 @@
/*
* exynos_adc.c - Support for ADC in EXYNOS SoCs
*
* 8 ~ 10 channel, 10/12-bit ADC
*
* Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <soc/samsung/exynos-powermode.h>
/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
#define ADC_V1_DLY(x) ((x) + 0x08)
#define ADC_V1_DATX(x) ((x) + 0x0C)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
/* S3C2410 ADC registers definitions */
#define ADC_S3C2410_MUX(x) ((x) + 0x18)
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
#define ADC_V2_CON2(x) ((x) + 0x04)
#define ADC_V2_STAT(x) ((x) + 0x08)
#define ADC_V2_INT_EN(x) ((x) + 0x10)
#define ADC_V2_INT_ST(x) ((x) + 0x14)
#define ADC_V2_VER(x) ((x) + 0x20)
/* Sharing ADC_V3 registers definitions */
#define ADC_V3_DAT(x) ((x) + 0x08)
#define ADC_V3_DAT_SUM(x) ((x) + 0x0C)
#define ADC_V3_DBG_DATA(x) ((x) + 0x1C)
/* Bit definitions for ADC_V1 */
#define ADC_V1_CON_RES (1u << 16)
#define ADC_V1_CON_PRSCEN (1u << 14)
#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY (1u << 2)
/* Bit definitions for S3C2410 ADC */
#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3)
#define ADC_S3C2410_DATX_MASK 0x3FF
#define ADC_S3C2416_CON_RES_SEL (1u << 3)
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
#define ADC_V2_CON1_SOFT_NON_RESET (1u << 1)
#define ADC_V2_CON2_OSEL (1u << 10)
#define ADC_V2_CON2_ESEL (1u << 9)
#define ADC_V2_CON2_HIGHF (1u << 8)
#define ADC_V2_CON2_C_TIME(x) (((x) & 7) << 4)
#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
#define ADC_V2_CON2_ACH_MASK 0xF
/* Bit definitions for ADC_V3 */
#define ADC_V3_DAT_FLAG (1u << 31)
#define MAX_ADC_V3_CHANNELS 8
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
/* Bit definitions common for ADC_V1, ADC_V2, ADC_V3 */
#define ADC_CON_EN_START (1u << 0)
#define ADC_DATX_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
struct clk *sclk;
unsigned int irq;
struct regulator *vdd;
bool needs_adc_phy;
struct completion completion;
u32 value;
unsigned int version;
int idle_ip_index;
};
struct exynos_adc_data {
int num_channels;
bool needs_sclk;
u32 mask;
void (*init_hw)(struct exynos_adc *info);
void (*exit_hw)(struct exynos_adc *info);
void (*clear_irq)(struct exynos_adc *info);
void (*start_conv)(struct exynos_adc *info, unsigned long addr);
irqreturn_t (*adc_isr)(int irq, void *dev_id);
};
static void exynos_adc_unprepare_clk(struct exynos_adc *info)
{
if (info->data->needs_sclk)
clk_unprepare(info->sclk);
clk_unprepare(info->clk);
}
static int exynos_adc_prepare_clk(struct exynos_adc *info)
{
int ret;
ret = clk_prepare(info->clk);
if (ret) {
dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_prepare(info->sclk);
if (ret) {
clk_unprepare(info->clk);
dev_err(info->dev,
"failed preparing sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
}
static void exynos_adc_disable_clk(struct exynos_adc *info)
{
if (info->data->needs_sclk)
clk_disable(info->sclk);
clk_disable(info->clk);
}
static int exynos_adc_enable_clk(struct exynos_adc *info)
{
int ret;
ret = clk_enable(info->clk);
if (ret) {
dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_enable(info->sclk);
if (ret) {
clk_disable(info->clk);
dev_err(info->dev,
"failed enabling sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
}
static int exynos_adc_enable_access(struct exynos_adc *info)
{
int ret;
exynos_update_ip_idle_status(info->idle_ip_index, 0);
if (info->needs_adc_phy)
writel(1, info->enable_reg);
if (info->vdd) {
ret = regulator_enable(info->vdd);
if (ret)
goto err;
}
ret = exynos_adc_prepare_clk(info);
if (ret)
goto err;
ret = exynos_adc_enable_clk(info);
if (ret)
goto err;
return 0;
err:
exynos_update_ip_idle_status(info->idle_ip_index, 1);
return ret;
}
static void exynos_adc_disable_access(struct exynos_adc *info)
{
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
if (info->vdd)
regulator_disable(info->vdd);
if (info->needs_adc_phy)
writel(0, info->enable_reg);
exynos_update_ip_idle_status(info->idle_ip_index, 1);
}
static void exynos_adc_v1_init_hw(struct exynos_adc *info)
{
u32 con1;
/* set default prescaler values and Enable prescaler */
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
/* Enable 12-bit ADC resolution */
con1 |= ADC_V1_CON_RES;
writel(con1, ADC_V1_CON(info->regs));
}
static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
{
u32 con;
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
writel(con, ADC_V1_CON(info->regs));
}
static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V1_INTCLR(info->regs));
}
static void exynos_adc_v1_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
writel(addr, ADC_V1_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static irqreturn_t exynos_adc_v1_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
u32 mask = info->data->mask;
/* Read value */
info->value = readl(ADC_V1_DATX(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
info->data->clear_irq(info);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
/* Enable 12 bit ADC resolution */
con1 = readl(ADC_V1_CON(info->regs));
con1 |= ADC_S3C2416_CON_RES_SEL;
writel(con1, ADC_V1_CON(info->regs));
/* Select channel for S3C2416 */
writel(addr, ADC_S3C2410_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c2416_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c2416_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
/* Select channel for S3C2433 */
writel(addr, ADC_S3C2410_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c2443_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c2443_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
con1 = readl(ADC_V1_CON(info->regs));
con1 &= ~ADC_S3C2410_CON_SELMUX(0x7);
con1 |= ADC_S3C2410_CON_SELMUX(addr);
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c24xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c64xx_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_s3c64xx_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_v2_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(6);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
{
u32 con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~(ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(7));
writel(con2, ADC_V2_CON2(info->regs));
/* Disable interrupts */
writel(0, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V2_INT_ST(info->regs));
}
static void exynos_adc_v2_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1, con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_ACH_MASK;
con2 |= ADC_V2_CON2_ACH_SEL(addr);
writel(con2, ADC_V2_CON2(info->regs));
con1 = readl(ADC_V2_CON1(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
}
static const struct exynos_adc_data exynos_adc_v2_data = {
.num_channels = MAX_ADC_V2_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static const struct exynos_adc_data exynos3250_adc_data = {
.num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_sclk = true,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_v3_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con1 = ADC_V2_CON1_SOFT_NON_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con2 = ADC_V2_CON2_C_TIME(6);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v3_exit_hw(struct exynos_adc *info)
{
u32 con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_C_TIME(7);
writel(con2, ADC_V2_CON2(info->regs));
/* Disable interrupts */
writel(0, ADC_V2_INT_EN(info->regs));
}
static irqreturn_t exynos_adc_v3_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
u32 mask = info->data->mask;
/* Read value */
info->value = readl(ADC_V3_DAT(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
info->data->clear_irq(info);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct exynos_adc_data exynos_adc_v3_data = {
.num_channels = MAX_ADC_V3_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v3_init_hw,
.exit_hw = exynos_adc_v3_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v3_isr,
};
static const struct of_device_id exynos_adc_match[] = {
{
.compatible = "samsung,s3c2410-adc",
.data = &exynos_adc_s3c24xx_data,
}, {
.compatible = "samsung,s3c2416-adc",
.data = &exynos_adc_s3c2416_data,
}, {
.compatible = "samsung,s3c2440-adc",
.data = &exynos_adc_s3c24xx_data,
}, {
.compatible = "samsung,s3c2443-adc",
.data = &exynos_adc_s3c2443_data,
}, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
}, {
.compatible = "samsung,exynos-adc-v2",
.data = &exynos_adc_v2_data,
}, {
.compatible = "samsung,exynos-adc-v3",
.data = &exynos_adc_v3_data,
}, {
.compatible = "samsung,exynos3250-adc",
.data = &exynos3250_adc_data,
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos_adc_match, pdev->dev.of_node);
return (struct exynos_adc_data *)match->data;
}
static int exynos_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
ret = exynos_adc_enable_access(info);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
enable_irq(info->irq);
if (info->data->init_hw)
info->data->init_hw(info);
/* Select the channel to be used and Trigger conversion */
if (info->data->start_conv)
info->data->start_conv(info, chan->address);
timeout = wait_for_completion_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
ret = -ETIMEDOUT;
} else {
*val = info->value;
*val2 = 0;
ret = IIO_VAL_INT;
}
if (info->data->exit_hw)
info->data->exit_hw(info);
disable_irq(info->irq);
exynos_adc_disable_access(info);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int exynos_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct exynos_adc *info = iio_priv(indio_dev);
int ret;
if (readval == NULL)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = exynos_adc_enable_access(info);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
*readval = readl(info->regs + reg);
exynos_adc_disable_access(info);
mutex_unlock(&indio_dev->mlock);
return 0;
}
static const struct iio_info exynos_adc_iio_info = {
.read_raw = &exynos_read_raw,
.debugfs_reg_access = &exynos_adc_reg_access,
.driver_module = THIS_MODULE,
};
#define ADC_CHANNEL(_index, _id) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.address = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.datasheet_name = _id, \
}
static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
ADC_CHANNEL(3, "adc3"),
ADC_CHANNEL(4, "adc4"),
ADC_CHANNEL(5, "adc5"),
ADC_CHANNEL(6, "adc6"),
ADC_CHANNEL(7, "adc7"),
ADC_CHANNEL(8, "adc8"),
ADC_CHANNEL(9, "adc9"),
};
static int exynos_adc_remove_devices(struct device *dev, void *c)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
int ret = -ENODEV;
int irq;
if (!np)
return ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
info->data = exynos_adc_get_data(pdev);
if (!info->data) {
dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
return -EINVAL;
}
if (of_find_property(np, "samsung,adc-phy-control", NULL))
info->needs_adc_phy = true;
else
info->needs_adc_phy = false;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
if (info->needs_adc_phy) {
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->enable_reg))
return PTR_ERR(info->enable_reg);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return irq;
}
info->irq = irq;
info->dev = &pdev->dev;
info->idle_ip_index = exynos_get_idle_ip_index(dev_name(&pdev->dev));
init_completion(&info->completion);
info->clk = devm_clk_get(&pdev->dev, "gate_adcif");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
return PTR_ERR(info->clk);
}
if (info->data->needs_sclk) {
info->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(info->sclk)) {
dev_err(&pdev->dev,
"failed getting sclk clock, err = %ld\n",
PTR_ERR(info->sclk));
return PTR_ERR(info->sclk);
}
}
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) {
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
PTR_ERR(info->vdd));
info->vdd = NULL;
}
exynos_update_ip_idle_status(info->idle_ip_index, 0);
if (info->vdd) {
ret = regulator_enable(info->vdd);
if (ret)
return ret;
}
ret = exynos_adc_prepare_clk(info);
if (ret)
goto err_disable_reg;
ret = exynos_adc_enable_clk(info);
if (ret)
goto err_unprepare_clk;
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &exynos_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = exynos_adc_iio_channels;
indio_dev->num_channels = info->data->num_channels;
ret = devm_request_irq(&pdev->dev, info->irq, info->data->adc_isr,
0, dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
info->irq);
goto err_disable_clk;
}
disable_irq(info->irq);
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
if (info->vdd)
regulator_disable(info->vdd);
exynos_update_ip_idle_status(info->idle_ip_index, 1);
ret = iio_device_register(indio_dev);
if (ret)
goto err_irq;
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
goto err_of_populate;
}
dev_info(&pdev->dev, "Probed successfully driver.\n");
return 0;
err_of_populate:
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
err_disable_clk:
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_clk(info);
err_unprepare_clk:
exynos_adc_unprepare_clk(info);
err_disable_reg:
if (info->vdd)
regulator_disable(info->vdd);
return ret;
}
static int exynos_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
int ret;
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
ret = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_access(info);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int exynos_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev);
int ret;
ret = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_access(info);
return 0;
}
static int exynos_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev);
int ret;
ret = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->init_hw)
info->data->init_hw(info);
exynos_adc_disable_access(info);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops,
exynos_adc_suspend,
exynos_adc_resume);
static struct platform_driver exynos_adc_driver = {
.probe = exynos_adc_probe,
.remove = exynos_adc_remove,
.driver = {
.name = "exynos-adc",
.of_match_table = exynos_adc_match,
},
};
module_platform_driver(exynos_adc_driver);
MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>");
MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,254 @@
/*
* TI LP8788 MFD - ADC driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/mfd/lp8788.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* register address */
#define LP8788_ADC_CONF 0x60
#define LP8788_ADC_RAW 0x61
#define LP8788_ADC_DONE 0x63
#define ADC_CONV_START 1
struct lp8788_adc {
struct lp8788 *lp;
struct iio_map *map;
struct mutex lock;
};
static const int lp8788_scale[LPADC_MAX] = {
[LPADC_VBATT_5P5] = 1343101,
[LPADC_VIN_CHG] = 3052503,
[LPADC_IBATT] = 610500,
[LPADC_IC_TEMP] = 61050,
[LPADC_VBATT_6P0] = 1465201,
[LPADC_VBATT_5P0] = 1221001,
[LPADC_ADC1] = 610500,
[LPADC_ADC2] = 610500,
[LPADC_VDD] = 1025641,
[LPADC_VCOIN] = 757020,
[LPADC_ADC3] = 610500,
[LPADC_ADC4] = 610500,
};
static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id,
int *val)
{
unsigned int msb;
unsigned int lsb;
unsigned int result;
u8 data;
u8 rawdata[2];
int size = ARRAY_SIZE(rawdata);
int retry = 5;
int ret;
data = (id << 1) | ADC_CONV_START;
ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data);
if (ret)
goto err_io;
/* retry until adc conversion is done */
data = 0;
while (retry--) {
usleep_range(100, 200);
ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data);
if (ret)
goto err_io;
/* conversion done */
if (data)
break;
}
ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size);
if (ret)
goto err_io;
msb = (rawdata[0] << 4) & 0x00000ff0;
lsb = (rawdata[1] >> 4) & 0x0000000f;
result = msb | lsb;
*val = result;
return 0;
err_io:
return ret;
}
static int lp8788_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct lp8788_adc *adc = iio_priv(indio_dev);
enum lp8788_adc_id id = chan->channel;
int ret;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = lp8788_scale[id] / 1000000;
*val2 = lp8788_scale[id] % 1000000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&adc->lock);
return ret;
}
static const struct iio_info lp8788_adc_info = {
.read_raw = &lp8788_adc_read_raw,
.driver_module = THIS_MODULE,
};
#define LP8788_CHAN(_id, _type) { \
.type = _type, \
.indexed = 1, \
.channel = LPADC_##_id, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = #_id, \
}
static const struct iio_chan_spec lp8788_adc_channels[] = {
[LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE),
[LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE),
[LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT),
[LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP),
[LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE),
[LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE),
[LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE),
[LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE),
[LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE),
[LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE),
[LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE),
[LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE),
};
/* default maps used by iio consumer (lp8788-charger driver) */
static struct iio_map lp8788_default_iio_maps[] = {
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_vbatt_5p0",
.adc_channel_label = "VBATT_5P0",
},
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_adc1",
.adc_channel_label = "ADC1",
},
{ }
};
static int lp8788_iio_map_register(struct iio_dev *indio_dev,
struct lp8788_platform_data *pdata,
struct lp8788_adc *adc)
{
struct iio_map *map;
int ret;
map = (!pdata || !pdata->adc_pdata) ?
lp8788_default_iio_maps : pdata->adc_pdata;
ret = iio_map_array_register(indio_dev, map);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
return ret;
}
adc->map = map;
return 0;
}
static int lp8788_adc_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct iio_dev *indio_dev;
struct lp8788_adc *adc;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->lp = lp;
platform_set_drvdata(pdev, indio_dev);
indio_dev->dev.of_node = pdev->dev.of_node;
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
return ret;
mutex_init(&adc->lock);
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &lp8788_adc_info;
indio_dev->channels = lp8788_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "iio dev register err: %d\n", ret);
goto err_iio_device;
}
return 0;
err_iio_device:
iio_map_array_unregister(indio_dev);
return ret;
}
static int lp8788_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
return 0;
}
static struct platform_driver lp8788_adc_driver = {
.probe = lp8788_adc_probe,
.remove = lp8788_adc_remove,
.driver = {
.name = LP8788_DEV_ADC,
},
};
module_platform_driver(lp8788_adc_driver);
MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver");
MODULE_AUTHOR("Milo Kim");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:lp8788-adc");

521
drivers/iio/adc/max1027.c Normal file
View file

@ -0,0 +1,521 @@
/*
* iio/adc/max1027.c
* Copyright (C) 2014 Philippe Reynes
*
* based on linux/drivers/iio/ad7923.c
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
* 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.
*
* max1027.c
*
* Partial support for max1027 and similar chips.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define MAX1027_CONV_REG BIT(7)
#define MAX1027_SETUP_REG BIT(6)
#define MAX1027_AVG_REG BIT(5)
#define MAX1027_RST_REG BIT(4)
/* conversion register */
#define MAX1027_TEMP BIT(0)
#define MAX1027_SCAN_0_N (0x00 << 1)
#define MAX1027_SCAN_N_M (0x01 << 1)
#define MAX1027_SCAN_N (0x02 << 1)
#define MAX1027_NOSCAN (0x03 << 1)
#define MAX1027_CHAN(n) ((n) << 3)
/* setup register */
#define MAX1027_UNIPOLAR 0x02
#define MAX1027_BIPOLAR 0x03
#define MAX1027_REF_MODE0 (0x00 << 2)
#define MAX1027_REF_MODE1 (0x01 << 2)
#define MAX1027_REF_MODE2 (0x02 << 2)
#define MAX1027_REF_MODE3 (0x03 << 2)
#define MAX1027_CKS_MODE0 (0x00 << 4)
#define MAX1027_CKS_MODE1 (0x01 << 4)
#define MAX1027_CKS_MODE2 (0x02 << 4)
#define MAX1027_CKS_MODE3 (0x03 << 4)
/* averaging register */
#define MAX1027_NSCAN_4 0x00
#define MAX1027_NSCAN_8 0x01
#define MAX1027_NSCAN_12 0x02
#define MAX1027_NSCAN_16 0x03
#define MAX1027_NAVG_4 (0x00 << 2)
#define MAX1027_NAVG_8 (0x01 << 2)
#define MAX1027_NAVG_16 (0x02 << 2)
#define MAX1027_NAVG_32 (0x03 << 2)
#define MAX1027_AVG_EN BIT(4)
enum max1027_id {
max1027,
max1029,
max1031,
};
static const struct spi_device_id max1027_id[] = {
{"max1027", max1027},
{"max1029", max1029},
{"max1031", max1031},
{}
};
MODULE_DEVICE_TABLE(spi, max1027_id);
#ifdef CONFIG_OF
static const struct of_device_id max1027_adc_dt_ids[] = {
{ .compatible = "maxim,max1027" },
{ .compatible = "maxim,max1029" },
{ .compatible = "maxim,max1031" },
{},
};
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
#endif
#define MAX1027_V_CHAN(index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = index + 1, \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
}
#define MAX1027_T_CHAN \
{ \
.type = IIO_TEMP, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = 0, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec max1027_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7)
};
static const struct iio_chan_spec max1029_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11)
};
static const struct iio_chan_spec max1031_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11),
MAX1027_V_CHAN(12),
MAX1027_V_CHAN(13),
MAX1027_V_CHAN(14),
MAX1027_V_CHAN(15)
};
static const unsigned long max1027_available_scan_masks[] = {
0x000001ff,
0x00000000,
};
static const unsigned long max1029_available_scan_masks[] = {
0x00001fff,
0x00000000,
};
static const unsigned long max1031_available_scan_masks[] = {
0x0001ffff,
0x00000000,
};
struct max1027_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
const unsigned long *available_scan_masks;
};
static const struct max1027_chip_info max1027_chip_info_tbl[] = {
[max1027] = {
.channels = max1027_channels,
.num_channels = ARRAY_SIZE(max1027_channels),
.available_scan_masks = max1027_available_scan_masks,
},
[max1029] = {
.channels = max1029_channels,
.num_channels = ARRAY_SIZE(max1029_channels),
.available_scan_masks = max1029_available_scan_masks,
},
[max1031] = {
.channels = max1031_channels,
.num_channels = ARRAY_SIZE(max1031_channels),
.available_scan_masks = max1031_available_scan_masks,
},
};
struct max1027_state {
const struct max1027_chip_info *info;
struct spi_device *spi;
struct iio_trigger *trig;
__be16 *buffer;
struct mutex lock;
u8 reg ____cacheline_aligned;
};
static int max1027_read_single_value(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
int ret;
struct max1027_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev)) {
dev_warn(&indio_dev->dev, "trigger mode already enabled");
return -EBUSY;
}
/* Start acquisition on conversion register write */
st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev,
"Failed to configure setup register\n");
return ret;
}
/* Configure conversion register with the requested chan */
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) |
MAX1027_NOSCAN | !!(chan->type == IIO_TEMP);
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev,
"Failed to configure conversion register\n");
return ret;
}
/*
* For an unknown reason, when we use the mode "10" (write
* conversion register), the interrupt doesn't occur every time.
* So we just wait 1 ms.
*/
mdelay(1);
/* Read result */
ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2);
if (ret < 0)
return ret;
*val = be16_to_cpu(st->buffer[0]);
return IIO_VAL_INT;
}
static int max1027_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = 0;
struct max1027_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = max1027_read_single_value(indio_dev, chan, val);
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
*val = 1;
*val2 = 8;
ret = IIO_VAL_FRACTIONAL;
break;
case IIO_VOLTAGE:
*val = 2500;
*val2 = 10;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
ret = -EINVAL;
break;
}
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&st->lock);
return ret;
}
static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct max1027_state *st = iio_priv(indio_dev);
u8 *val = (u8 *)st->buffer;
if (readval != NULL)
return -EINVAL;
*val = (u8)writeval;
return spi_write(st->spi, val, 1);
}
static int max1027_validate_trigger(struct iio_dev *indio_dev,
struct iio_trigger *trig)
{
struct max1027_state *st = iio_priv(indio_dev);
if (st->trig != trig)
return -EINVAL;
return 0;
}
static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct max1027_state *st = iio_priv(indio_dev);
int ret;
if (state) {
/* Start acquisition on cnvst */
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 |
MAX1027_REF_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
/* Scan from 0 to max */
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) |
MAX1027_SCAN_N_M | MAX1027_TEMP;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
} else {
/* Start acquisition on conversion register write */
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 |
MAX1027_REF_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
}
return 0;
}
static int max1027_validate_device(struct iio_trigger *trig,
struct iio_dev *indio_dev)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
if (indio != indio_dev)
return -EINVAL;
return 0;
}
static irqreturn_t max1027_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = (struct iio_poll_func *)private;
struct iio_dev *indio_dev = pf->indio_dev;
struct max1027_state *st = iio_priv(indio_dev);
pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private);
/* fill buffer with all channel */
spi_read(st->spi, st->buffer, indio_dev->masklength * 2);
iio_push_to_buffers(indio_dev, st->buffer);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_trigger_ops max1027_trigger_ops = {
.owner = THIS_MODULE,
.validate_device = &max1027_validate_device,
.set_trigger_state = &max1027_set_trigger_state,
};
static const struct iio_info max1027_info = {
.driver_module = THIS_MODULE,
.read_raw = &max1027_read_raw,
.validate_trigger = &max1027_validate_trigger,
.debugfs_reg_access = &max1027_debugfs_reg_access,
};
static int max1027_probe(struct spi_device *spi)
{
int ret;
struct iio_dev *indio_dev;
struct max1027_state *st;
pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi);
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
pr_err("Can't allocate iio device\n");
return -ENOMEM;
}
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->spi = spi;
st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
mutex_init(&st->lock);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &max1027_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
indio_dev->available_scan_masks = st->info->available_scan_masks;
st->buffer = devm_kmalloc(&indio_dev->dev,
indio_dev->num_channels * 2,
GFP_KERNEL);
if (st->buffer == NULL) {
dev_err(&indio_dev->dev, "Can't allocate bufffer\n");
return -ENOMEM;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&max1027_trigger_handler, NULL);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
return ret;
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
indio_dev->name);
if (st->trig == NULL) {
ret = -ENOMEM;
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
goto fail_trigger_alloc;
}
st->trig->ops = &max1027_trigger_ops;
st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
iio_trigger_register(st->trig);
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_FALLING,
spi->dev.driver->name, st->trig);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
goto fail_dev_register;
}
/* Disable averaging */
st->reg = MAX1027_AVG_REG;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to configure averaging register\n");
goto fail_dev_register;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to register iio device\n");
goto fail_dev_register;
}
return 0;
fail_dev_register:
fail_trigger_alloc:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int max1027_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static struct spi_driver max1027_driver = {
.driver = {
.name = "max1027",
.owner = THIS_MODULE,
},
.probe = max1027_probe,
.remove = max1027_remove,
.id_table = max1027_id,
};
module_spi_driver(max1027_driver);
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
MODULE_LICENSE("GPL v2");

1701
drivers/iio/adc/max1363.c Normal file

File diff suppressed because it is too large Load diff

249
drivers/iio/adc/mcp320x.c Normal file
View file

@ -0,0 +1,249 @@
/*
* Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
*
* Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
* Datasheet can be found here:
* http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#define MCP_SINGLE_ENDED (1 << 3)
#define MCP_START_BIT (1 << 4)
enum {
mcp3204,
mcp3208,
};
struct mcp320x {
struct spi_device *spi;
struct spi_message msg;
struct spi_transfer transfer[2];
u8 tx_buf;
u8 rx_buf[2];
struct regulator *reg;
struct mutex lock;
};
static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
{
int ret;
adc->tx_buf = msg;
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
return ((adc->rx_buf[0] & 0x3f) << 6) |
(adc->rx_buf[1] >> 2);
}
static int mcp320x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct mcp320x *adc = iio_priv(indio_dev);
int ret = -EINVAL;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (channel->differential)
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | channel->address);
else
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | MCP_SINGLE_ENDED |
channel->address);
if (ret < 0)
goto out;
*val = ret;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
/* Digital output code = (4096 * Vin) / Vref */
ret = regulator_get_voltage(adc->reg);
if (ret < 0)
goto out;
*val = ret / 1000;
*val2 = 12;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
break;
}
out:
mutex_unlock(&adc->lock);
return ret;
}
#define MCP320X_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num), \
.address = (num), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
#define MCP320X_VOLTAGE_CHANNEL_DIFF(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num * 2), \
.channel2 = (num * 2 + 1), \
.address = (num * 2), \
.differential = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec mcp3204_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
MCP320X_VOLTAGE_CHANNEL(2),
MCP320X_VOLTAGE_CHANNEL(3),
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
};
static const struct iio_chan_spec mcp3208_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
MCP320X_VOLTAGE_CHANNEL(2),
MCP320X_VOLTAGE_CHANNEL(3),
MCP320X_VOLTAGE_CHANNEL(4),
MCP320X_VOLTAGE_CHANNEL(5),
MCP320X_VOLTAGE_CHANNEL(6),
MCP320X_VOLTAGE_CHANNEL(7),
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
MCP320X_VOLTAGE_CHANNEL_DIFF(2),
MCP320X_VOLTAGE_CHANNEL_DIFF(3),
};
static const struct iio_info mcp320x_info = {
.read_raw = mcp320x_read_raw,
.driver_module = THIS_MODULE,
};
struct mcp3208_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
[mcp3204] = {
.channels = mcp3204_channels,
.num_channels = ARRAY_SIZE(mcp3204_channels)
},
[mcp3208] = {
.channels = mcp3208_channels,
.num_channels = ARRAY_SIZE(mcp3208_channels)
},
};
static int mcp320x_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mcp320x *adc;
const struct mcp3208_chip_info *chip_info;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp320x_info;
chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
adc->transfer[0].tx_buf = &adc->tx_buf;
adc->transfer[0].len = sizeof(adc->tx_buf);
adc->transfer[1].rx_buf = adc->rx_buf;
adc->transfer[1].len = sizeof(adc->rx_buf);
spi_message_init_with_transfers(&adc->msg, adc->transfer,
ARRAY_SIZE(adc->transfer));
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret < 0)
return ret;
mutex_init(&adc->lock);
ret = iio_device_register(indio_dev);
if (ret < 0)
goto reg_disable;
return 0;
reg_disable:
regulator_disable(adc->reg);
return ret;
}
static int mcp320x_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct mcp320x *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
static const struct spi_device_id mcp320x_id[] = {
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
static struct spi_driver mcp320x_driver = {
.driver = {
.name = "mcp320x",
.owner = THIS_MODULE,
},
.probe = mcp320x_probe,
.remove = mcp320x_remove,
.id_table = mcp320x_id,
};
module_spi_driver(mcp320x_driver);
MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
MODULE_LICENSE("GPL v2");

417
drivers/iio/adc/mcp3422.c Normal file
View file

@ -0,0 +1,417 @@
/*
* mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
*
* Copyright (C) 2013, Angelo Compagnucci
* Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
* http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
*
* This driver exports the value of analog input voltage to sysfs, the
* voltage unit is nV.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* Masks */
#define MCP3422_CHANNEL_MASK 0x60
#define MCP3422_PGA_MASK 0x03
#define MCP3422_SRATE_MASK 0x0C
#define MCP3422_SRATE_240 0x0
#define MCP3422_SRATE_60 0x1
#define MCP3422_SRATE_15 0x2
#define MCP3422_SRATE_3 0x3
#define MCP3422_PGA_1 0
#define MCP3422_PGA_2 1
#define MCP3422_PGA_4 2
#define MCP3422_PGA_8 3
#define MCP3422_CONT_SAMPLING 0x10
#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5)
#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK)
#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2)
#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK)
#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK)
#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK)
#define MCP3422_CHAN(_index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
| BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const int mcp3422_scales[4][4] = {
{ 1000000, 500000, 250000, 125000 },
{ 250000 , 125000, 62500 , 31250 },
{ 62500 , 31250 , 15625 , 7812 },
{ 15625 , 7812 , 3906 , 1953 } };
/* Constant msleep times for data acquisitions */
static const int mcp3422_read_times[4] = {
[MCP3422_SRATE_240] = 1000 / 240,
[MCP3422_SRATE_60] = 1000 / 60,
[MCP3422_SRATE_15] = 1000 / 15,
[MCP3422_SRATE_3] = 1000 / 3 };
/* sample rates to integer conversion table */
static const int mcp3422_sample_rates[4] = {
[MCP3422_SRATE_240] = 240,
[MCP3422_SRATE_60] = 60,
[MCP3422_SRATE_15] = 15,
[MCP3422_SRATE_3] = 3 };
/* sample rates to sign extension table */
static const int mcp3422_sign_extend[4] = {
[MCP3422_SRATE_240] = 11,
[MCP3422_SRATE_60] = 13,
[MCP3422_SRATE_15] = 15,
[MCP3422_SRATE_3] = 17 };
/* Client data (each client gets its own) */
struct mcp3422 {
struct i2c_client *i2c;
u8 id;
u8 config;
u8 pga[4];
struct mutex lock;
};
static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig)
{
int ret;
mutex_lock(&adc->lock);
ret = i2c_master_send(adc->i2c, &newconfig, 1);
if (ret > 0) {
adc->config = newconfig;
ret = 0;
}
mutex_unlock(&adc->lock);
return ret;
}
static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config)
{
int ret = 0;
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
u8 buf[4] = {0, 0, 0, 0};
u32 temp;
if (sample_rate == MCP3422_SRATE_3) {
ret = i2c_master_recv(adc->i2c, buf, 4);
temp = buf[0] << 16 | buf[1] << 8 | buf[2];
*config = buf[3];
} else {
ret = i2c_master_recv(adc->i2c, buf, 3);
temp = buf[0] << 8 | buf[1];
*config = buf[2];
}
*value = sign_extend32(temp, mcp3422_sign_extend[sample_rate]);
return ret;
}
static int mcp3422_read_channel(struct mcp3422 *adc,
struct iio_chan_spec const *channel, int *value)
{
int ret;
u8 config;
u8 req_channel = channel->channel;
if (req_channel != MCP3422_CHANNEL(adc->config)) {
config = adc->config;
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_PGA_MASK;
config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
ret = mcp3422_update_config(adc, config);
if (ret < 0)
return ret;
msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
}
return mcp3422_read(adc, value, &config);
}
static int mcp3422_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *val1,
int *val2, long mask)
{
struct mcp3422 *adc = iio_priv(iio);
int err;
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
u8 pga = MCP3422_PGA(adc->config);
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = mcp3422_read_channel(adc, channel, val1);
if (err < 0)
return -EINVAL;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val1 = 0;
*val2 = mcp3422_scales[sample_rate][pga];
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
*val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)];
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int mcp3422_write_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int val1,
int val2, long mask)
{
struct mcp3422 *adc = iio_priv(iio);
u8 temp;
u8 config = adc->config;
u8 req_channel = channel->channel;
u8 sample_rate = MCP3422_SAMPLE_RATE(config);
u8 i;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (val1 != 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) {
if (val2 == mcp3422_scales[sample_rate][i]) {
adc->pga[req_channel] = i;
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_PGA_MASK;
config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
return mcp3422_update_config(adc, config);
}
}
return -EINVAL;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (val1) {
case 240:
temp = MCP3422_SRATE_240;
break;
case 60:
temp = MCP3422_SRATE_60;
break;
case 15:
temp = MCP3422_SRATE_15;
break;
case 3:
if (adc->id > 4)
return -EINVAL;
temp = MCP3422_SRATE_3;
break;
default:
return -EINVAL;
}
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_SRATE_MASK;
config |= MCP3422_SAMPLE_RATE_VALUE(temp);
return mcp3422_update_config(adc, config);
default:
break;
}
return -EINVAL;
}
static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static ssize_t mcp3422_show_samp_freqs(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
if (adc->id > 4)
return sprintf(buf, "240 60 15\n");
return sprintf(buf, "240 60 15 3\n");
}
static ssize_t mcp3422_show_scales(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n",
mcp3422_scales[sample_rate][0],
mcp3422_scales[sample_rate][1],
mcp3422_scales[sample_rate][2],
mcp3422_scales[sample_rate][3]);
}
static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO,
mcp3422_show_samp_freqs, NULL, 0);
static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
mcp3422_show_scales, NULL, 0);
static struct attribute *mcp3422_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group mcp3422_attribute_group = {
.attrs = mcp3422_attributes,
};
static const struct iio_chan_spec mcp3422_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
};
static const struct iio_chan_spec mcp3424_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
MCP3422_CHAN(2),
MCP3422_CHAN(3),
};
static const struct iio_info mcp3422_info = {
.read_raw = mcp3422_read_raw,
.write_raw = mcp3422_write_raw,
.write_raw_get_fmt = mcp3422_write_raw_get_fmt,
.attrs = &mcp3422_attribute_group,
.driver_module = THIS_MODULE,
};
static int mcp3422_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct mcp3422 *adc;
int err;
u8 config;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->i2c = client;
adc->id = (u8)(id->driver_data);
mutex_init(&adc->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp3422_info;
switch (adc->id) {
case 2:
case 3:
case 6:
case 7:
indio_dev->channels = mcp3422_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels);
break;
case 4:
case 8:
indio_dev->channels = mcp3424_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels);
break;
}
/* meaningful default configuration */
config = (MCP3422_CONT_SAMPLING
| MCP3422_CHANNEL_VALUE(1)
| MCP3422_PGA_VALUE(MCP3422_PGA_1)
| MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240));
mcp3422_update_config(adc, config);
err = devm_iio_device_register(&client->dev, indio_dev);
if (err < 0)
return err;
i2c_set_clientdata(client, indio_dev);
return 0;
}
static const struct i2c_device_id mcp3422_id[] = {
{ "mcp3422", 2 },
{ "mcp3423", 3 },
{ "mcp3424", 4 },
{ "mcp3426", 6 },
{ "mcp3427", 7 },
{ "mcp3428", 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3422_id);
#ifdef CONFIG_OF
static const struct of_device_id mcp3422_of_match[] = {
{ .compatible = "mcp3422" },
{ }
};
MODULE_DEVICE_TABLE(of, mcp3422_of_match);
#endif
static struct i2c_driver mcp3422_driver = {
.driver = {
.name = "mcp3422",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mcp3422_of_match),
},
.probe = mcp3422_probe,
.id_table = mcp3422_id,
};
module_i2c_driver(mcp3422_driver);
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,173 @@
/*
* MEN 16z188 Analog to Digial Converter
*
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mcb.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#define Z188_ADC_MAX_CHAN 8
#define Z188_ADC_GAIN 0x0700000
#define Z188_MODE_VOLTAGE BIT(27)
#define Z188_CFG_AUTO 0x1
#define Z188_CTRL_REG 0x40
#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
#define ADC_OVR(x) ((x) & 0x1)
struct z188_adc {
struct resource *mem;
void __iomem *base;
};
#define Z188_ADC_CHANNEL(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static const struct iio_chan_spec z188_adc_iio_channels[] = {
Z188_ADC_CHANNEL(0),
Z188_ADC_CHANNEL(1),
Z188_ADC_CHANNEL(2),
Z188_ADC_CHANNEL(3),
Z188_ADC_CHANNEL(4),
Z188_ADC_CHANNEL(5),
Z188_ADC_CHANNEL(6),
Z188_ADC_CHANNEL(7),
};
static int z188_iio_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
struct z188_adc *adc = iio_priv(iio_dev);
int ret;
u16 tmp;
switch (info) {
case IIO_CHAN_INFO_RAW:
tmp = readw(adc->base + chan->channel * 4);
if (ADC_OVR(tmp)) {
dev_info(&iio_dev->dev,
"Oversampling error on ADC channel %d\n",
chan->channel);
return -EIO;
}
*val = ADC_DATA(tmp);
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct iio_info z188_adc_info = {
.read_raw = &z188_iio_read_raw,
.driver_module = THIS_MODULE,
};
static void men_z188_config_channels(void __iomem *addr)
{
int i;
u32 cfg;
u32 ctl;
ctl = readl(addr + Z188_CTRL_REG);
ctl |= Z188_CFG_AUTO;
writel(ctl, addr + Z188_CTRL_REG);
for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
cfg = readl(addr + i);
cfg &= ~Z188_ADC_GAIN;
cfg |= Z188_MODE_VOLTAGE;
writel(cfg, addr + i);
}
}
static int men_z188_probe(struct mcb_device *dev,
const struct mcb_device_id *id)
{
struct z188_adc *adc;
struct iio_dev *indio_dev;
struct resource *mem;
indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
indio_dev->name = "z188-adc";
indio_dev->dev.parent = &dev->dev;
indio_dev->info = &z188_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = z188_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
mem = mcb_request_mem(dev, "z188-adc");
if (IS_ERR(mem))
return PTR_ERR(mem);
adc->base = ioremap(mem->start, resource_size(mem));
if (adc->base == NULL)
goto err;
men_z188_config_channels(adc->base);
adc->mem = mem;
mcb_set_drvdata(dev, indio_dev);
return iio_device_register(indio_dev);
err:
mcb_release_mem(mem);
return -ENXIO;
}
static void men_z188_remove(struct mcb_device *dev)
{
struct iio_dev *indio_dev = mcb_get_drvdata(dev);
struct z188_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iounmap(adc->base);
mcb_release_mem(adc->mem);
}
static const struct mcb_device_id men_z188_ids[] = {
{ .device = 0xbc },
{ }
};
MODULE_DEVICE_TABLE(mcb, men_z188_ids);
static struct mcb_driver men_z188_driver = {
.driver = {
.name = "z188-adc",
.owner = THIS_MODULE,
},
.probe = men_z188_probe,
.remove = men_z188_remove,
.id_table = men_z188_ids,
};
module_mcb_driver(men_z188_driver);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
MODULE_ALIAS("mcb:16z188");

582
drivers/iio/adc/nau7802.c Normal file
View file

@ -0,0 +1,582 @@
/*
* Driver for the Nuvoton NAU7802 ADC
*
* Copyright 2013 Free Electrons
*
* Licensed under the GPLv2 or later.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/log2.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define NAU7802_REG_PUCTRL 0x00
#define NAU7802_PUCTRL_RR(x) (x << 0)
#define NAU7802_PUCTRL_RR_BIT NAU7802_PUCTRL_RR(1)
#define NAU7802_PUCTRL_PUD(x) (x << 1)
#define NAU7802_PUCTRL_PUD_BIT NAU7802_PUCTRL_PUD(1)
#define NAU7802_PUCTRL_PUA(x) (x << 2)
#define NAU7802_PUCTRL_PUA_BIT NAU7802_PUCTRL_PUA(1)
#define NAU7802_PUCTRL_PUR(x) (x << 3)
#define NAU7802_PUCTRL_PUR_BIT NAU7802_PUCTRL_PUR(1)
#define NAU7802_PUCTRL_CS(x) (x << 4)
#define NAU7802_PUCTRL_CS_BIT NAU7802_PUCTRL_CS(1)
#define NAU7802_PUCTRL_CR(x) (x << 5)
#define NAU7802_PUCTRL_CR_BIT NAU7802_PUCTRL_CR(1)
#define NAU7802_PUCTRL_AVDDS(x) (x << 7)
#define NAU7802_PUCTRL_AVDDS_BIT NAU7802_PUCTRL_AVDDS(1)
#define NAU7802_REG_CTRL1 0x01
#define NAU7802_CTRL1_VLDO(x) (x << 3)
#define NAU7802_CTRL1_GAINS(x) (x)
#define NAU7802_CTRL1_GAINS_BITS 0x07
#define NAU7802_REG_CTRL2 0x02
#define NAU7802_CTRL2_CHS(x) (x << 7)
#define NAU7802_CTRL2_CRS(x) (x << 4)
#define NAU7802_SAMP_FREQ_320 0x07
#define NAU7802_CTRL2_CHS_BIT NAU7802_CTRL2_CHS(1)
#define NAU7802_REG_ADC_B2 0x12
#define NAU7802_REG_ADC_B1 0x13
#define NAU7802_REG_ADC_B0 0x14
#define NAU7802_REG_ADC_CTRL 0x15
#define NAU7802_MIN_CONVERSIONS 6
struct nau7802_state {
struct i2c_client *client;
s32 last_value;
struct mutex lock;
struct mutex data_lock;
u32 vref_mv;
u32 conversion_count;
u32 min_conversions;
u8 sample_rate;
u32 scale_avail[8];
struct completion value_ok;
};
#define NAU7802_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan), \
.scan_index = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) \
}
static const struct iio_chan_spec nau7802_chan_array[] = {
NAU7802_CHANNEL(0),
NAU7802_CHANNEL(1),
};
static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
10, 10, 10, 320};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
static struct attribute *nau7802_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group nau7802_attribute_group = {
.attrs = nau7802_attributes,
};
static int nau7802_set_gain(struct nau7802_state *st, int gain)
{
int ret;
mutex_lock(&st->lock);
st->conversion_count = 0;
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
if (ret < 0)
goto nau7802_sysfs_set_gain_out;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
(ret & (~NAU7802_CTRL1_GAINS_BITS)) |
gain);
nau7802_sysfs_set_gain_out:
mutex_unlock(&st->lock);
return ret;
}
static int nau7802_read_conversion(struct nau7802_state *st)
{
int data;
mutex_lock(&st->data_lock);
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B2);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value = data << 16;
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B1);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value |= data << 8;
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B0);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value |= data;
st->last_value = sign_extend32(st->last_value, 23);
nau7802_read_conversion_out:
mutex_unlock(&st->data_lock);
return data;
}
/*
* Conversions are synchronised on the rising edge of NAU7802_PUCTRL_CS_BIT
*/
static int nau7802_sync(struct nau7802_state *st)
{
int ret;
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
ret | NAU7802_PUCTRL_CS_BIT);
return ret;
}
static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct nau7802_state *st = iio_priv(indio_dev);
int status;
status = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (status < 0)
return IRQ_HANDLED;
if (!(status & NAU7802_PUCTRL_CR_BIT))
return IRQ_NONE;
if (nau7802_read_conversion(st) < 0)
return IRQ_HANDLED;
/*
* Because there is actually only one ADC for both channels, we have to
* wait for enough conversions to happen before getting a significant
* value when changing channels and the values are far apart.
*/
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
complete_all(&st->value_ok);
return IRQ_HANDLED;
}
static int nau7802_read_irq(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
reinit_completion(&st->value_ok);
enable_irq(st->client->irq);
nau7802_sync(st);
/* read registers to ensure we flush everything */
ret = nau7802_read_conversion(st);
if (ret < 0)
goto read_chan_info_failure;
/* Wait for a conversion to finish */
ret = wait_for_completion_interruptible_timeout(&st->value_ok,
msecs_to_jiffies(1000));
if (ret == 0)
ret = -ETIMEDOUT;
if (ret < 0)
goto read_chan_info_failure;
disable_irq(st->client->irq);
*val = st->last_value;
return IIO_VAL_INT;
read_chan_info_failure:
disable_irq(st->client->irq);
return ret;
}
static int nau7802_read_poll(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
nau7802_sync(st);
/* read registers to ensure we flush everything */
ret = nau7802_read_conversion(st);
if (ret < 0)
return ret;
/*
* Because there is actually only one ADC for both channels, we have to
* wait for enough conversions to happen before getting a significant
* value when changing channels and the values are far appart.
*/
do {
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
while (!(ret & NAU7802_PUCTRL_CR_BIT)) {
if (st->sample_rate != NAU7802_SAMP_FREQ_320)
msleep(20);
else
mdelay(4);
ret = i2c_smbus_read_byte_data(st->client,
NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
}
ret = nau7802_read_conversion(st);
if (ret < 0)
return ret;
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
} while (st->conversion_count < NAU7802_MIN_CONVERSIONS);
*val = st->last_value;
return IIO_VAL_INT;
}
static int nau7802_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
/*
* Select the channel to use
* - Channel 1 is value 0 in the CHS register
* - Channel 2 is value 1 in the CHS register
*/
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL2);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
if (((ret & NAU7802_CTRL2_CHS_BIT) && !chan->channel) ||
(!(ret & NAU7802_CTRL2_CHS_BIT) &&
chan->channel)) {
st->conversion_count = 0;
ret = i2c_smbus_write_byte_data(st->client,
NAU7802_REG_CTRL2,
NAU7802_CTRL2_CHS(chan->channel) |
NAU7802_CTRL2_CRS(st->sample_rate));
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
}
if (st->client->irq)
ret = nau7802_read_irq(indio_dev, chan, val);
else
ret = nau7802_read_poll(indio_dev, chan, val);
mutex_unlock(&st->lock);
return ret;
case IIO_CHAN_INFO_SCALE:
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
if (ret < 0)
return ret;
/*
* We have 24 bits of signed data, that means 23 bits of data
* plus the sign bit
*/
*val = st->vref_mv;
*val2 = 23 + (ret & NAU7802_CTRL1_GAINS_BITS);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = nau7802_sample_freq_avail[st->sample_rate];
*val2 = 0;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int nau7802_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct nau7802_state *st = iio_priv(indio_dev);
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i])
return nau7802_set_gain(st, i);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0; i < ARRAY_SIZE(nau7802_sample_freq_avail); i++)
if (val == nau7802_sample_freq_avail[i]) {
mutex_lock(&st->lock);
st->sample_rate = i;
st->conversion_count = 0;
ret = i2c_smbus_write_byte_data(st->client,
NAU7802_REG_CTRL2,
NAU7802_CTRL2_CRS(st->sample_rate));
mutex_unlock(&st->lock);
return ret;
}
break;
default:
break;
}
return -EINVAL;
}
static int nau7802_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
return IIO_VAL_INT_PLUS_NANO;
}
static const struct iio_info nau7802_info = {
.driver_module = THIS_MODULE,
.read_raw = &nau7802_read_raw,
.write_raw = &nau7802_write_raw,
.write_raw_get_fmt = nau7802_write_raw_get_fmt,
.attrs = &nau7802_attribute_group,
};
static int nau7802_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct nau7802_state *st;
struct device_node *np = client->dev.of_node;
int i, ret;
u8 data;
u32 tmp = 0;
if (!client->dev.of_node) {
dev_err(&client->dev, "No device tree node available.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &nau7802_info;
st->client = client;
/* Reset the device */
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
NAU7802_PUCTRL_RR_BIT);
if (ret < 0)
return ret;
/* Enter normal operation mode */
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
NAU7802_PUCTRL_PUD_BIT);
if (ret < 0)
return ret;
/*
* After about 200 usecs, the device should be ready and then
* the Power Up bit will be set to 1. If not, wait for it.
*/
udelay(210);
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
if (!(ret & NAU7802_PUCTRL_PUR_BIT))
return ret;
of_property_read_u32(np, "nuvoton,vldo", &tmp);
st->vref_mv = tmp;
data = NAU7802_PUCTRL_PUD_BIT | NAU7802_PUCTRL_PUA_BIT |
NAU7802_PUCTRL_CS_BIT;
if (tmp >= 2400)
data |= NAU7802_PUCTRL_AVDDS_BIT;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, data);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_ADC_CTRL, 0x30);
if (ret < 0)
return ret;
if (tmp >= 2400) {
data = NAU7802_CTRL1_VLDO((4500 - tmp) / 300);
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
data);
if (ret < 0)
return ret;
}
/* Populate available ADC input ranges */
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
st->scale_avail[i] = (((u64)st->vref_mv) * 1000000000ULL)
>> (23 + i);
init_completion(&st->value_ok);
/*
* The ADC fires continuously and we can't do anything about
* it. So we need to have the IRQ disabled by default, and we
* will enable them back when we will need them..
*/
if (client->irq) {
ret = request_threaded_irq(client->irq,
NULL,
nau7802_eoc_trigger,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
client->dev.driver->name,
indio_dev);
if (ret) {
/*
* What may happen here is that our IRQ controller is
* not able to get level interrupt but this is required
* by this ADC as when going over 40 sample per second,
* the interrupt line may stay high between conversions.
* So, we continue no matter what but we switch to
* polling mode.
*/
dev_info(&client->dev,
"Failed to allocate IRQ, using polling mode\n");
client->irq = 0;
} else
disable_irq(client->irq);
}
if (!client->irq) {
/*
* We are polling, use the fastest sample rate by
* default
*/
st->sample_rate = NAU7802_SAMP_FREQ_320;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2,
NAU7802_CTRL2_CRS(st->sample_rate));
if (ret)
goto error_free_irq;
}
/* Setup the ADC channels available on the board */
indio_dev->num_channels = ARRAY_SIZE(nau7802_chan_array);
indio_dev->channels = nau7802_chan_array;
mutex_init(&st->lock);
mutex_init(&st->data_lock);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Couldn't register the device.\n");
goto error_device_register;
}
return 0;
error_device_register:
mutex_destroy(&st->lock);
mutex_destroy(&st->data_lock);
error_free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
return ret;
}
static int nau7802_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct nau7802_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_destroy(&st->lock);
mutex_destroy(&st->data_lock);
if (client->irq)
free_irq(client->irq, indio_dev);
return 0;
}
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
static const struct of_device_id nau7802_dt_ids[] = {
{ .compatible = "nuvoton,nau7802" },
{},
};
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
static struct i2c_driver nau7802_driver = {
.probe = nau7802_probe,
.remove = nau7802_remove,
.id_table = nau7802_i2c_id,
.driver = {
.name = "nau7802",
.of_match_table = nau7802_dt_ids,
},
};
module_i2c_driver(nau7802_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Nuvoton NAU7802 ADC Driver");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");

View file

@ -0,0 +1,316 @@
/*
* Rockchip Successive Approximation Register (SAR) A/D Converter
* Copyright (C) 2014 ROCKCHIP, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#define SARADC_DATA 0x00
#define SARADC_DATA_MASK 0x3ff
#define SARADC_STAS 0x04
#define SARADC_STAS_BUSY BIT(0)
#define SARADC_CTRL 0x08
#define SARADC_CTRL_IRQ_STATUS BIT(6)
#define SARADC_CTRL_IRQ_ENABLE BIT(5)
#define SARADC_CTRL_POWER_CTRL BIT(3)
#define SARADC_CTRL_CHN_MASK 0x7
#define SARADC_DLY_PU_SOC 0x0c
#define SARADC_DLY_PU_SOC_MASK 0x3f
#define SARADC_BITS 10
#define SARADC_TIMEOUT msecs_to_jiffies(100)
struct rockchip_saradc {
void __iomem *regs;
struct clk *pclk;
struct clk *clk;
struct completion completion;
struct regulator *vref;
u16 last_val;
};
static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct rockchip_saradc *info = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
/* 8 clock periods as delay between power up and start cmd */
writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
/* Select the channel to be used and trigger conversion */
writel(SARADC_CTRL_POWER_CTRL
| (chan->channel & SARADC_CTRL_CHN_MASK)
| SARADC_CTRL_IRQ_ENABLE,
info->regs + SARADC_CTRL);
if (!wait_for_completion_timeout(&info->completion,
SARADC_TIMEOUT)) {
writel_relaxed(0, info->regs + SARADC_CTRL);
mutex_unlock(&indio_dev->mlock);
return -ETIMEDOUT;
}
*val = info->last_val;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(info->vref);
if (ret < 0) {
dev_err(&indio_dev->dev, "failed to get voltage\n");
return ret;
}
*val = ret / 1000;
*val2 = SARADC_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
{
struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id;
/* Read value */
info->last_val = readl_relaxed(info->regs + SARADC_DATA);
info->last_val &= SARADC_DATA_MASK;
/* Clear irq & power down adc */
writel_relaxed(0, info->regs + SARADC_CTRL);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct iio_info rockchip_saradc_iio_info = {
.read_raw = rockchip_saradc_read_raw,
.driver_module = THIS_MODULE,
};
#define ADC_CHANNEL(_index, _id) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = _id, \
}
static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
};
static int rockchip_saradc_probe(struct platform_device *pdev)
{
struct rockchip_saradc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
int ret;
int irq;
if (!np)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
init_completion(&info->completion);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return irq;
}
ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
0, dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
return ret;
}
info->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(info->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
return PTR_ERR(info->pclk);
}
info->clk = devm_clk_get(&pdev->dev, "saradc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get adc clock\n");
return PTR_ERR(info->clk);
}
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref)) {
dev_err(&pdev->dev, "failed to get regulator, %ld\n",
PTR_ERR(info->vref));
return PTR_ERR(info->vref);
}
/*
* Use a default of 1MHz for the converter clock.
* This may become user-configurable in the future.
*/
ret = clk_set_rate(info->clk, 1000000);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
return ret;
}
ret = regulator_enable(info->vref);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable vref regulator\n");
return ret;
}
ret = clk_prepare_enable(info->pclk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable pclk\n");
goto err_reg_voltage;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable converter clock\n");
goto err_pclk;
}
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &rockchip_saradc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = rockchip_saradc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels);
ret = iio_device_register(indio_dev);
if (ret)
goto err_clk;
return 0;
err_clk:
clk_disable_unprepare(info->clk);
err_pclk:
clk_disable_unprepare(info->pclk);
err_reg_voltage:
regulator_disable(info->vref);
return ret;
}
static int rockchip_saradc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct rockchip_saradc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
clk_disable_unprepare(info->clk);
clk_disable_unprepare(info->pclk);
regulator_disable(info->vref);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rockchip_saradc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rockchip_saradc *info = iio_priv(indio_dev);
clk_disable_unprepare(info->clk);
clk_disable_unprepare(info->pclk);
regulator_disable(info->vref);
return 0;
}
static int rockchip_saradc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rockchip_saradc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vref);
if (ret)
return ret;
ret = clk_prepare_enable(info->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(info->clk);
if (ret)
return ret;
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
rockchip_saradc_suspend, rockchip_saradc_resume);
static const struct of_device_id rockchip_saradc_match[] = {
{ .compatible = "rockchip,saradc" },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
static struct platform_driver rockchip_saradc_driver = {
.probe = rockchip_saradc_probe,
.remove = rockchip_saradc_remove,
.driver = {
.name = "rockchip-saradc",
.owner = THIS_MODULE,
.of_match_table = rockchip_saradc_match,
.pm = &rockchip_saradc_pm_ops,
},
};
module_platform_driver(rockchip_saradc_driver);

View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2012 Avionic Design GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
struct adc081c {
struct i2c_client *i2c;
struct regulator *ref;
};
#define REG_CONV_RES 0x00
static int adc081c_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *value,
int *shift, long mask)
{
struct adc081c *adc = iio_priv(iio);
int err;
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES);
if (err < 0)
return err;
*value = (err >> 4) & 0xff;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
err = regulator_get_voltage(adc->ref);
if (err < 0)
return err;
*value = err / 1000;
*shift = 8;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static const struct iio_chan_spec adc081c_channel = {
.type = IIO_VOLTAGE,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
};
static const struct iio_info adc081c_info = {
.read_raw = adc081c_read_raw,
.driver_module = THIS_MODULE,
};
static int adc081c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *iio;
struct adc081c *adc;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
return -ENOMEM;
adc = iio_priv(iio);
adc->i2c = client;
adc->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(adc->ref))
return PTR_ERR(adc->ref);
err = regulator_enable(adc->ref);
if (err < 0)
return err;
iio->dev.parent = &client->dev;
iio->name = dev_name(&client->dev);
iio->modes = INDIO_DIRECT_MODE;
iio->info = &adc081c_info;
iio->channels = &adc081c_channel;
iio->num_channels = 1;
err = iio_device_register(iio);
if (err < 0)
goto regulator_disable;
i2c_set_clientdata(client, iio);
return 0;
regulator_disable:
regulator_disable(adc->ref);
return err;
}
static int adc081c_remove(struct i2c_client *client)
{
struct iio_dev *iio = i2c_get_clientdata(client);
struct adc081c *adc = iio_priv(iio);
iio_device_unregister(iio);
regulator_disable(adc->ref);
return 0;
}
static const struct i2c_device_id adc081c_id[] = {
{ "adc081c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
#ifdef CONFIG_OF
static const struct of_device_id adc081c_of_match[] = {
{ .compatible = "ti,adc081c" },
{ }
};
MODULE_DEVICE_TABLE(of, adc081c_of_match);
#endif
static struct i2c_driver adc081c_driver = {
.driver = {
.name = "adc081c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(adc081c_of_match),
},
.probe = adc081c_probe,
.remove = adc081c_remove,
.id_table = adc081c_id,
};
module_i2c_driver(adc081c_driver);
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,179 @@
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Driver for Texas Instruments' ADC128S052 ADC chip.
* Datasheet can be found here:
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
struct adc128 {
struct spi_device *spi;
struct regulator *reg;
struct mutex lock;
u8 buffer[2] ____cacheline_aligned;
};
static int adc128_adc_conversion(struct adc128 *adc, u8 channel)
{
int ret;
mutex_lock(&adc->lock);
adc->buffer[0] = channel << 3;
adc->buffer[1] = 0;
ret = spi_write(adc->spi, &adc->buffer, 2);
if (ret < 0) {
mutex_unlock(&adc->lock);
return ret;
}
ret = spi_read(adc->spi, &adc->buffer, 2);
mutex_unlock(&adc->lock);
if (ret < 0)
return ret;
return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF);
}
static int adc128_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct adc128 *adc = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = adc128_adc_conversion(adc, channel->channel);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(adc->reg);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define ADC128_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec adc128_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
ADC128_VOLTAGE_CHANNEL(2),
ADC128_VOLTAGE_CHANNEL(3),
ADC128_VOLTAGE_CHANNEL(4),
ADC128_VOLTAGE_CHANNEL(5),
ADC128_VOLTAGE_CHANNEL(6),
ADC128_VOLTAGE_CHANNEL(7),
};
static const struct iio_info adc128_info = {
.read_raw = adc128_read_raw,
.driver_module = THIS_MODULE,
};
static int adc128_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc128 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc128_info;
indio_dev->channels = adc128_channels;
indio_dev->num_channels = ARRAY_SIZE(adc128_channels);
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret < 0)
return ret;
mutex_init(&adc->lock);
ret = iio_device_register(indio_dev);
return ret;
}
static int adc128_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adc128 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0},
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.owner = THIS_MODULE,
},
.probe = adc128_probe,
.remove = adc128_remove,
.id_table = adc128_id,
};
module_spi_driver(adc128_driver);
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
MODULE_DESCRIPTION("Texas Instruments ADC128S052");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,558 @@
/*
* TI ADC MFD driver
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <linux/mfd/ti_am335x_tscadc.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
struct tiadc_device {
struct ti_tscadc_dev *mfd_tscadc;
int channels;
u8 channel_line[8];
u8 channel_step[8];
int buffer_en_ch_steps;
u16 data[8];
};
static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
{
return readl(adc->mfd_tscadc->tscadc_base + reg);
}
static void tiadc_writel(struct tiadc_device *adc, unsigned int reg,
unsigned int val)
{
writel(val, adc->mfd_tscadc->tscadc_base + reg);
}
static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
{
u32 step_en;
step_en = ((1 << adc_dev->channels) - 1);
step_en <<= TOTAL_STEPS - adc_dev->channels + 1;
return step_en;
}
static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev,
struct iio_chan_spec const *chan)
{
int i;
for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
if (chan->channel == adc_dev->channel_line[i]) {
u32 step;
step = adc_dev->channel_step[i];
/* +1 for the charger */
return 1 << (step + 1);
}
}
WARN_ON(1);
return 0;
}
static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
{
return 1 << adc_dev->channel_step[chan];
}
static void tiadc_step_config(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int stepconfig;
int i, steps;
/*
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC.
*
* Steps backwards i.e. from 16 towards 0 are used by ADC
* depending on number of input lines needed.
* Channel would represent which analog input
* needs to be given to ADC to digitalize data.
*/
steps = TOTAL_STEPS - adc_dev->channels;
if (iio_buffer_enabled(indio_dev))
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
| STEPCONFIG_MODE_SWCNT;
else
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
for (i = 0; i < adc_dev->channels; i++) {
int chan;
chan = adc_dev->channel_line[i];
tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
stepconfig | STEPCONFIG_INP(chan));
tiadc_writel(adc_dev, REG_STEPDELAY(steps),
STEPCONFIG_OPENDLY);
adc_dev->channel_step[i] = steps;
steps++;
}
}
static irqreturn_t tiadc_irq_h(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int status, config;
status = tiadc_readl(adc_dev, REG_IRQSTATUS);
/*
* ADC and touchscreen share the IRQ line.
* FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only
*/
if (status & IRQENB_FIFO1OVRRUN) {
/* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */
config = tiadc_readl(adc_dev, REG_CTRL);
config &= ~(CNTRLREG_TSCSSENB);
tiadc_writel(adc_dev, REG_CTRL, config);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN
| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
return IRQ_HANDLED;
} else if (status & IRQENB_FIFO1THRES) {
/* Disable irq and wake worker thread */
tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES);
return IRQ_WAKE_THREAD;
}
return IRQ_NONE;
}
static irqreturn_t tiadc_worker_h(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i, k, fifo1count, read;
u16 *data = adc_dev->data;
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (k = 0; k < fifo1count; k = k + i) {
for (i = 0; i < (indio_dev->scan_bytes)/2; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1);
data[i] = read & FIFOREAD_DATA_MASK;
}
iio_push_to_buffers(indio_dev, (u8 *) data);
}
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES);
tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
return IRQ_HANDLED;
}
static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i, fifo1count, read;
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
IRQENB_FIFO1OVRRUN |
IRQENB_FIFO1UNDRFLW));
/* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++)
read = tiadc_readl(adc_dev, REG_FIFO1);
return 0;
}
static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct iio_buffer *buffer = indio_dev->buffer;
unsigned int enb = 0;
u8 bit;
tiadc_step_config(indio_dev);
for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels)
enb |= (get_adc_step_bit(adc_dev, bit) << 1);
adc_dev->buffer_en_ch_steps = enb;
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES
| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES
| IRQENB_FIFO1OVRRUN);
return 0;
}
static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int fifo1count, i, read;
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps);
adc_dev->buffer_en_ch_steps = 0;
/* Flush FIFO of leftover data in the time it takes to disable adc */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++)
read = tiadc_readl(adc_dev, REG_FIFO1);
return 0;
}
static int tiadc_buffer_postdisable(struct iio_dev *indio_dev)
{
tiadc_step_config(indio_dev);
return 0;
}
static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = {
.preenable = &tiadc_buffer_preenable,
.postenable = &tiadc_buffer_postenable,
.predisable = &tiadc_buffer_predisable,
.postdisable = &tiadc_buffer_postdisable,
};
static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
irqreturn_t (*pollfunc_bh)(int irq, void *p),
irqreturn_t (*pollfunc_th)(int irq, void *p),
int irq,
unsigned long flags,
const struct iio_buffer_setup_ops *setup_ops)
{
struct iio_buffer *buffer;
int ret;
buffer = iio_kfifo_allocate(indio_dev);
if (!buffer)
return -ENOMEM;
iio_device_attach_buffer(indio_dev, buffer);
ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh,
flags, indio_dev->name, indio_dev);
if (ret)
goto error_kfifo_free;
indio_dev->setup_ops = setup_ops;
indio_dev->modes |= INDIO_BUFFER_HARDWARE;
ret = iio_buffer_register(indio_dev,
indio_dev->channels,
indio_dev->num_channels);
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(irq, indio_dev);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
}
static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
free_irq(adc_dev->mfd_tscadc->irq, indio_dev);
iio_kfifo_free(indio_dev->buffer);
iio_buffer_unregister(indio_dev);
}
static const char * const chan_name_ain[] = {
"AIN0",
"AIN1",
"AIN2",
"AIN3",
"AIN4",
"AIN5",
"AIN6",
"AIN7",
};
static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct iio_chan_spec *chan_array;
struct iio_chan_spec *chan;
int i;
indio_dev->num_channels = channels;
chan_array = kcalloc(channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (chan_array == NULL)
return -ENOMEM;
chan = chan_array;
for (i = 0; i < channels; i++, chan++) {
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = adc_dev->channel_line[i];
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->datasheet_name = chan_name_ain[chan->channel];
chan->scan_index = i;
chan->scan_type.sign = 'u';
chan->scan_type.realbits = 12;
chan->scan_type.storagebits = 16;
}
indio_dev->channels = chan_array;
return 0;
}
static void tiadc_channels_remove(struct iio_dev *indio_dev)
{
kfree(indio_dev->channels);
}
static int tiadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i, map_val;
unsigned int fifo1count, read, stepid;
bool found = false;
u32 step_en;
unsigned long timeout;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
step_en = get_adc_chan_step_mask(adc_dev, chan);
if (!step_en)
return -EINVAL;
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
while (fifo1count--)
tiadc_readl(adc_dev, REG_FIFO1);
am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
timeout = jiffies + usecs_to_jiffies
(IDLE_TIMEOUT * adc_dev->channels);
/* Wait for Fifo threshold interrupt */
while (1) {
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
if (fifo1count)
break;
if (time_after(jiffies, timeout)) {
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
return -EAGAIN;
}
}
map_val = adc_dev->channel_step[chan->scan_index];
/*
* We check the complete FIFO. We programmed just one entry but in case
* something went wrong we left empty handed (-EAGAIN previously) and
* then the value apeared somehow in the FIFO we would have two entries.
* Therefore we read every item and keep only the latest version of the
* requested channel.
*/
for (i = 0; i < fifo1count; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1);
stepid = read & FIFOREAD_CHNLID_MASK;
stepid = stepid >> 0x10;
if (stepid == map_val) {
read = read & FIFOREAD_DATA_MASK;
found = true;
*val = (u16) read;
}
}
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
if (found == false)
return -EBUSY;
return IIO_VAL_INT;
}
static const struct iio_info tiadc_info = {
.read_raw = &tiadc_read_raw,
.driver_module = THIS_MODULE,
};
static int tiadc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct tiadc_device *adc_dev;
struct device_node *node = pdev->dev.of_node;
struct property *prop;
const __be32 *cur;
int err;
u32 val;
int channels = 0;
if (!node) {
dev_err(&pdev->dev, "Could not find valid DT data.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct tiadc_device));
if (indio_dev == NULL) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
return -ENOMEM;
}
adc_dev = iio_priv(indio_dev);
adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
adc_dev->channel_line[channels] = val;
channels++;
}
adc_dev->channels = channels;
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tiadc_info;
tiadc_step_config(indio_dev);
tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD);
err = tiadc_channel_init(indio_dev, adc_dev->channels);
if (err < 0)
return err;
err = tiadc_iio_buffered_hardware_setup(indio_dev,
&tiadc_worker_h,
&tiadc_irq_h,
adc_dev->mfd_tscadc->irq,
IRQF_SHARED,
&tiadc_buffer_setup_ops);
if (err)
goto err_free_channels;
err = iio_device_register(indio_dev);
if (err)
goto err_buffer_unregister;
platform_set_drvdata(pdev, indio_dev);
return 0;
err_buffer_unregister:
tiadc_iio_buffered_hardware_remove(indio_dev);
err_free_channels:
tiadc_channels_remove(indio_dev);
return err;
}
static int tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
u32 step_en;
iio_device_unregister(indio_dev);
tiadc_iio_buffered_hardware_remove(indio_dev);
tiadc_channels_remove(indio_dev);
step_en = get_adc_step_mask(adc_dev);
am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
return 0;
}
#ifdef CONFIG_PM
static int tiadc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (!device_may_wakeup(tscadc_dev->dev)) {
idle = tiadc_readl(adc_dev, REG_CTRL);
idle &= ~(CNTRLREG_TSCSSENB);
tiadc_writel(adc_dev, REG_CTRL, (idle |
CNTRLREG_POWERDOWN));
}
return 0;
}
static int tiadc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int restore;
/* Make sure ADC is powered up */
restore = tiadc_readl(adc_dev, REG_CTRL);
restore &= ~(CNTRLREG_POWERDOWN);
tiadc_writel(adc_dev, REG_CTRL, restore);
tiadc_step_config(indio_dev);
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc,
adc_dev->buffer_en_ch_steps);
return 0;
}
static const struct dev_pm_ops tiadc_pm_ops = {
.suspend = tiadc_suspend,
.resume = tiadc_resume,
};
#define TIADC_PM_OPS (&tiadc_pm_ops)
#else
#define TIADC_PM_OPS NULL
#endif
static const struct of_device_id ti_adc_dt_ids[] = {
{ .compatible = "ti,am3359-adc", },
{ }
};
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static struct platform_driver tiadc_driver = {
.driver = {
.name = "TI-am335x-adc",
.pm = TIADC_PM_OPS,
.of_match_table = ti_adc_dt_ids,
},
.probe = tiadc_probe,
.remove = tiadc_remove,
};
module_platform_driver(tiadc_driver);
MODULE_DESCRIPTION("TI ADC controller driver");
MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,895 @@
/*
*
* TWL4030 MADC module driver-This driver monitors the real time
* conversion of analog signals like battery temperature,
* battery type, battery level etc.
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* J Keerthy <j-keerthy@ti.com>
*
* Based on twl4030-madc.c
* Copyright (C) 2008 Nokia Corporation
* Mikko Ylinen <mikko.k.ylinen@nokia.com>
*
* Amit Kucheria <amit.kucheria@canonical.com>
*
* 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 program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/i2c/twl.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
/**
* struct twl4030_madc_data - a container for madc info
* @dev: Pointer to device structure for madc
* @lock: Mutex protecting this data structure
* @requests: Array of request struct corresponding to SW1, SW2 and RT
* @use_second_irq: IRQ selection (main or co-processor)
* @imr: Interrupt mask register of MADC
* @isr: Interrupt status register of MADC
*/
struct twl4030_madc_data {
struct device *dev;
struct mutex lock; /* mutex protecting this data structure */
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
bool use_second_irq;
u8 imr;
u8 isr;
};
static int twl4030_madc_read(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct twl4030_madc_data *madc = iio_priv(iio_dev);
struct twl4030_madc_request req;
int ret;
req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
req.channels = BIT(chan->channel);
req.active = false;
req.func_cb = NULL;
req.type = TWL4030_MADC_WAIT;
req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
*val = req.rbuf[chan->channel];
return IIO_VAL_INT;
}
static const struct iio_info twl4030_madc_iio_info = {
.read_raw = &twl4030_madc_read,
.driver_module = THIS_MODULE,
};
#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
.type = _type, \
.channel = _channel, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
BIT(IIO_CHAN_INFO_PROCESSED), \
.datasheet_name = _name, \
.indexed = 1, \
}
static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
};
static struct twl4030_madc_data *twl4030_madc;
struct twl4030_prescale_divider_ratios {
s16 numerator;
s16 denominator;
};
static const struct twl4030_prescale_divider_ratios
twl4030_divider_ratios[16] = {
{1, 1}, /* CHANNEL 0 No Prescaler */
{1, 1}, /* CHANNEL 1 No Prescaler */
{6, 10}, /* CHANNEL 2 */
{6, 10}, /* CHANNEL 3 */
{6, 10}, /* CHANNEL 4 */
{6, 10}, /* CHANNEL 5 */
{6, 10}, /* CHANNEL 6 */
{6, 10}, /* CHANNEL 7 */
{3, 14}, /* CHANNEL 8 */
{1, 3}, /* CHANNEL 9 */
{1, 1}, /* CHANNEL 10 No Prescaler */
{15, 100}, /* CHANNEL 11 */
{1, 4}, /* CHANNEL 12 */
{1, 1}, /* CHANNEL 13 Reserved channels */
{1, 1}, /* CHANNEL 14 Reseved channels */
{5, 11}, /* CHANNEL 15 */
};
/* Conversion table from -3 to 55 degrees Celcius */
static int twl4030_therm_tbl[] = {
30800, 29500, 28300, 27100,
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
3550
};
/*
* Structure containing the registers
* of different conversion methods supported by MADC.
* Hardware or RT real time conversion request initiated by external host
* processor for RT Signal conversions.
* External host processors can also request for non RT conversions
* SW1 and SW2 software conversions also called asynchronous or GPC request.
*/
static
const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
[TWL4030_MADC_RT] = {
.sel = TWL4030_MADC_RTSELECT_LSB,
.avg = TWL4030_MADC_RTAVERAGE_LSB,
.rbase = TWL4030_MADC_RTCH0_LSB,
},
[TWL4030_MADC_SW1] = {
.sel = TWL4030_MADC_SW1SELECT_LSB,
.avg = TWL4030_MADC_SW1AVERAGE_LSB,
.rbase = TWL4030_MADC_GPCH0_LSB,
.ctrl = TWL4030_MADC_CTRL_SW1,
},
[TWL4030_MADC_SW2] = {
.sel = TWL4030_MADC_SW2SELECT_LSB,
.avg = TWL4030_MADC_SW2AVERAGE_LSB,
.rbase = TWL4030_MADC_GPCH0_LSB,
.ctrl = TWL4030_MADC_CTRL_SW2,
},
};
/**
* twl4030_madc_channel_raw_read() - Function to read a particular channel value
* @madc: pointer to struct twl4030_madc_data
* @reg: lsb of ADC Channel
*
* Return: 0 on success, an error code otherwise.
*/
static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
{
u16 val;
int ret;
/*
* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the address of LSB register
*/
ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
if (ret) {
dev_err(madc->dev, "unable to read register 0x%X\n", reg);
return ret;
}
return (int)(val >> 6);
}
/*
* Return battery temperature in degrees Celsius
* Or < 0 on failure.
*/
static int twl4030battery_temperature(int raw_volt)
{
u8 val;
int temp, curr, volt, res, ret;
volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
/* Getting and calculating the supply current in micro amperes */
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
REG_BCICTL2);
if (ret < 0)
return ret;
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
/* Getting and calculating the thermistor resistance in ohms */
res = volt * 1000 / curr;
/* calculating temperature */
for (temp = 58; temp >= 0; temp--) {
int actual = twl4030_therm_tbl[temp];
if ((actual - res) >= 0)
break;
}
return temp + 1;
}
static int twl4030battery_current(int raw_volt)
{
int ret;
u8 val;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
TWL4030_BCI_BCICTL1);
if (ret)
return ret;
if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
else /* slope of 0.88 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
}
/*
* Function to read channel values
* @madc - pointer to twl4030_madc_data struct
* @reg_base - Base address of the first channel
* @Channels - 16 bit bitmap. If the bit is set, channel's value is read
* @buf - The channel values are stored here. if read fails error
* @raw - Return raw values without conversion
* value is stored
* Returns the number of successfully read channels.
*/
static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
u8 reg_base, unsigned
long channels, int *buf,
bool raw)
{
int count = 0;
int i;
u8 reg;
for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
reg = reg_base + (2 * i);
buf[i] = twl4030_madc_channel_raw_read(madc, reg);
if (buf[i] < 0) {
dev_err(madc->dev, "Unable to read register 0x%X\n",
reg);
return buf[i];
}
if (raw) {
count++;
continue;
}
switch (i) {
case 10:
buf[i] = twl4030battery_current(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading current\n");
return buf[i];
} else {
count++;
buf[i] = buf[i] - 750;
}
break;
case 1:
buf[i] = twl4030battery_temperature(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading temperature\n");
return buf[i];
} else {
buf[i] -= 3;
count++;
}
break;
default:
count++;
/* Analog Input (V) = conv_result * step_size / R
* conv_result = decimal value of 10-bit conversion
* result
* step size = 1.5 / (2 ^ 10 -1)
* R = Prescaler ratio for input channels.
* Result given in mV hence multiplied by 1000.
*/
buf[i] = (buf[i] * 3 * 1000 *
twl4030_divider_ratios[i].denominator)
/ (2 * 1023 *
twl4030_divider_ratios[i].numerator);
}
}
return count;
}
/*
* Enables irq.
* @madc - pointer to twl4030_madc_data struct
* @id - irq number to be enabled
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
* corresponding to RT, SW1, SW2 conversion requests.
* If the i2c read fails it returns an error else returns 0.
*/
static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
return ret;
}
val &= ~(1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
}
/*
* Disables irq.
* @madc - pointer to twl4030_madc_data struct
* @id - irq number to be disabled
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
* corresponding to RT, SW1, SW2 conversion requests.
* Returns error if i2c read/write fails.
*/
static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
return ret;
}
val |= (1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
}
static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
{
struct twl4030_madc_data *madc = _madc;
const struct twl4030_madc_conversion_method *method;
u8 isr_val, imr_val;
int i, len, ret;
struct twl4030_madc_request *r;
mutex_lock(&madc->lock);
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
if (ret) {
dev_err(madc->dev, "unable to read isr register 0x%X\n",
madc->isr);
goto err_i2c;
}
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
goto err_i2c;
}
isr_val &= ~imr_val;
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
if (!(isr_val & (1 << i)))
continue;
ret = twl4030_madc_disable_irq(madc, i);
if (ret < 0)
dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
madc->requests[i].result_pending = 1;
}
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
/* No pending results for this method, move to next one */
if (!r->result_pending)
continue;
method = &twl4030_conversion_methods[r->method];
/* Read results */
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */
r->result_pending = 0;
r->active = 0;
}
mutex_unlock(&madc->lock);
return IRQ_HANDLED;
err_i2c:
/*
* In case of error check whichever request is active
* and service the same.
*/
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
if (r->active == 0)
continue;
method = &twl4030_conversion_methods[r->method];
/* Read results */
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */
r->result_pending = 0;
r->active = 0;
}
mutex_unlock(&madc->lock);
return IRQ_HANDLED;
}
static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
struct twl4030_madc_request *req)
{
struct twl4030_madc_request *p;
int ret;
p = &madc->requests[req->method];
memcpy(p, req, sizeof(*req));
ret = twl4030_madc_enable_irq(madc, req->method);
if (ret < 0) {
dev_err(madc->dev, "enable irq failed!!\n");
return ret;
}
return 0;
}
/*
* Function which enables the madc conversion
* by writing to the control register.
* @madc - pointer to twl4030_madc_data struct
* @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
* corresponding to RT SW1 or SW2 conversion methods.
* Returns 0 if succeeds else a negative error value
*/
static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
int conv_method)
{
const struct twl4030_madc_conversion_method *method;
int ret = 0;
if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
return -ENOTSUPP;
method = &twl4030_conversion_methods[conv_method];
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
method->ctrl);
if (ret) {
dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
method->ctrl);
return ret;
}
return 0;
}
/*
* Function that waits for conversion to be ready
* @madc - pointer to twl4030_madc_data struct
* @timeout_ms - timeout value in milliseconds
* @status_reg - ctrl register
* returns 0 if succeeds else a negative error value
*/
static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
unsigned int timeout_ms,
u8 status_reg)
{
unsigned long timeout;
int ret;
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
u8 reg;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
if (ret) {
dev_err(madc->dev,
"unable to read status register 0x%X\n",
status_reg);
return ret;
}
if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
return 0;
usleep_range(500, 2000);
} while (!time_after(jiffies, timeout));
dev_err(madc->dev, "conversion timeout!\n");
return -EAGAIN;
}
/*
* An exported function which can be called from other kernel drivers.
* @req twl4030_madc_request structure
* req->rbuf will be filled with read values of channels based on the
* channel index. If a particular channel reading fails there will
* be a negative error value in the corresponding array element.
* returns 0 if succeeds else error value
*/
int twl4030_madc_conversion(struct twl4030_madc_request *req)
{
const struct twl4030_madc_conversion_method *method;
int ret;
if (!req || !twl4030_madc)
return -EINVAL;
mutex_lock(&twl4030_madc->lock);
if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
ret = -EINVAL;
goto out;
}
/* Do we have a conversion request ongoing */
if (twl4030_madc->requests[req->method].active) {
ret = -EBUSY;
goto out;
}
method = &twl4030_conversion_methods[req->method];
/* Select channels to be converted */
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write sel register 0x%X\n", method->sel);
goto out;
}
/* Select averaging for all channels if do_avg is set */
if (req->do_avg) {
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write avg register 0x%X\n",
method->avg);
goto out;
}
}
if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
ret = twl4030_madc_set_irq(twl4030_madc, req);
if (ret < 0)
goto out;
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
ret = 0;
goto out;
}
/* With RT method we should not be here anymore */
if (req->method == TWL4030_MADC_RT) {
ret = -EINVAL;
goto out;
}
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
/* Wait until conversion is ready (ctrl register returns EOC) */
ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
if (ret) {
twl4030_madc->requests[req->method].active = 0;
goto out;
}
ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
req->channels, req->rbuf, req->raw);
twl4030_madc->requests[req->method].active = 0;
out:
mutex_unlock(&twl4030_madc->lock);
return ret;
}
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
int twl4030_get_madc_conversion(int channel_no)
{
struct twl4030_madc_request req;
int temp = 0;
int ret;
req.channels = (1 << channel_no);
req.method = TWL4030_MADC_SW2;
req.active = 0;
req.raw = 0;
req.func_cb = NULL;
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
if (req.rbuf[channel_no] > 0)
temp = req.rbuf[channel_no];
return temp;
}
EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
/**
* twl4030_madc_set_current_generator() - setup bias current
*
* @madc: pointer to twl4030_madc_data struct
* @chan: can be one of the two values:
* TWL4030_BCI_ITHEN
* Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN
* Enables bias current for main battery temperature sensing
* @on: enable or disable chan.
*
* Function to enable or disable bias current for
* main battery type reading or temperature sensing
*/
static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
int chan, int on)
{
int ret;
int regmask;
u8 regval;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
TWL4030_BCI_BCICTL1);
return ret;
}
regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
if (on)
regval |= regmask;
else
regval &= ~regmask;
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
TWL4030_BCI_BCICTL1);
return ret;
}
return 0;
}
/*
* Function that sets MADC software power on bit to enable MADC
* @madc - pointer to twl4030_madc_data struct
* @on - Enable or disable MADC software power on bit.
* returns error if i2c read/write fails else 0
*/
static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
{
u8 regval;
int ret;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_MADC_CTRL1);
if (ret) {
dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
TWL4030_MADC_CTRL1);
return ret;
}
if (on)
regval |= TWL4030_MADC_MADCON;
else
regval &= ~TWL4030_MADC_MADCON;
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
if (ret) {
dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
TWL4030_MADC_CTRL1);
return ret;
}
return 0;
}
/*
* Initialize MADC and request for threaded irq
*/
static int twl4030_madc_probe(struct platform_device *pdev)
{
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int irq, ret;
u8 regval;
struct iio_dev *iio_dev = NULL;
if (!pdata && !np) {
dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
return -EINVAL;
}
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
if (!iio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
madc = iio_priv(iio_dev);
madc->dev = &pdev->dev;
iio_dev->name = dev_name(&pdev->dev);
iio_dev->dev.parent = &pdev->dev;
iio_dev->dev.of_node = pdev->dev.of_node;
iio_dev->info = &twl4030_madc_iio_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = twl4030_madc_iio_channels;
iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
* as modem. Hence two separate ISR and IMR registers.
*/
if (pdata)
madc->use_second_irq = (pdata->irq_line != 1);
else
madc->use_second_irq = of_property_read_bool(np,
"ti,system-uses-second-madc-irq");
madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
TWL4030_MADC_IMR1;
madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
TWL4030_MADC_ISR1;
ret = twl4030_madc_set_power(madc, 1);
if (ret < 0)
return ret;
ret = twl4030_madc_set_current_generator(madc, 0, 1);
if (ret < 0)
goto err_current_generator;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
TWL4030_BCI_BCICTL1);
goto err_i2c;
}
regval |= TWL4030_BCI_MESBAT;
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
TWL4030_BCI_BCICTL1);
goto err_i2c;
}
/* Check that MADC clock is on */
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
if (ret) {
dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
TWL4030_REG_GPBR1);
goto err_i2c;
}
/* If MADC clk is not on, turn it on */
if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
dev_info(&pdev->dev, "clk disabled, enabling\n");
regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
TWL4030_REG_GPBR1);
if (ret) {
dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
TWL4030_REG_GPBR1);
goto err_i2c;
}
}
platform_set_drvdata(pdev, iio_dev);
mutex_init(&madc->lock);
irq = platform_get_irq(pdev, 0);
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl4030_madc_threaded_irq_handler,
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
dev_err(&pdev->dev, "could not request irq\n");
goto err_i2c;
}
twl4030_madc = madc;
ret = iio_device_register(iio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio device\n");
goto err_i2c;
}
return 0;
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
twl4030_madc_set_power(madc, 0);
return ret;
}
static int twl4030_madc_remove(struct platform_device *pdev)
{
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
struct twl4030_madc_data *madc = iio_priv(iio_dev);
iio_device_unregister(iio_dev);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id twl_madc_of_match[] = {
{ .compatible = "ti,twl4030-madc", },
{ },
};
MODULE_DEVICE_TABLE(of, twl_madc_of_match);
#endif
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
.remove = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.of_match_table = of_match_ptr(twl_madc_of_match),
},
};
module_platform_driver(twl4030_madc_driver);
MODULE_DESCRIPTION("TWL4030 ADC driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("J Keerthy");
MODULE_ALIAS("platform:twl4030_madc");

File diff suppressed because it is too large Load diff

741
drivers/iio/adc/vf610_adc.c Normal file
View file

@ -0,0 +1,741 @@
/*
* Freescale Vybrid vf610 ADC driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/driver.h>
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "vf610-adc"
/* Vybrid/IMX ADC registers */
#define VF610_REG_ADC_HC0 0x00
#define VF610_REG_ADC_HC1 0x04
#define VF610_REG_ADC_HS 0x08
#define VF610_REG_ADC_R0 0x0c
#define VF610_REG_ADC_R1 0x10
#define VF610_REG_ADC_CFG 0x14
#define VF610_REG_ADC_GC 0x18
#define VF610_REG_ADC_GS 0x1c
#define VF610_REG_ADC_CV 0x20
#define VF610_REG_ADC_OFS 0x24
#define VF610_REG_ADC_CAL 0x28
#define VF610_REG_ADC_PCTL 0x30
/* Configuration register field define */
#define VF610_ADC_MODE_BIT8 0x00
#define VF610_ADC_MODE_BIT10 0x04
#define VF610_ADC_MODE_BIT12 0x08
#define VF610_ADC_MODE_MASK 0x0c
#define VF610_ADC_BUSCLK2_SEL 0x01
#define VF610_ADC_ALTCLK_SEL 0x02
#define VF610_ADC_ADACK_SEL 0x03
#define VF610_ADC_ADCCLK_MASK 0x03
#define VF610_ADC_CLK_DIV2 0x20
#define VF610_ADC_CLK_DIV4 0x40
#define VF610_ADC_CLK_DIV8 0x60
#define VF610_ADC_CLK_MASK 0x60
#define VF610_ADC_ADLSMP_LONG 0x10
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
#define VF610_ADC_REFSEL_VALT 0x100
#define VF610_ADC_REFSEL_VBG 0x1000
#define VF610_ADC_ADTRG_HARD 0x2000
#define VF610_ADC_AVGS_8 0x4000
#define VF610_ADC_AVGS_16 0x8000
#define VF610_ADC_AVGS_32 0xC000
#define VF610_ADC_AVGS_MASK 0xC000
#define VF610_ADC_OVWREN 0x10000
/* General control register field define */
#define VF610_ADC_ADACKEN 0x1
#define VF610_ADC_DMAEN 0x2
#define VF610_ADC_ACREN 0x4
#define VF610_ADC_ACFGT 0x8
#define VF610_ADC_ACFE 0x10
#define VF610_ADC_AVGEN 0x20
#define VF610_ADC_ADCON 0x40
#define VF610_ADC_CAL 0x80
/* Other field define */
#define VF610_ADC_ADCHC(x) ((x) & 0xF)
#define VF610_ADC_AIEN (0x1 << 7)
#define VF610_ADC_CONV_DISABLE 0x1F
#define VF610_ADC_HS_COCO0 0x1
#define VF610_ADC_CALF 0x2
#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET,
VF610_ADCIOC_ALTCLK_SET,
VF610_ADCIOC_ADACK_SET,
};
enum vol_ref {
VF610_ADCIOC_VR_VREF_SET,
VF610_ADCIOC_VR_VALT_SET,
VF610_ADCIOC_VR_VBG_SET,
};
enum average_sel {
VF610_ADC_SAMPLE_1,
VF610_ADC_SAMPLE_4,
VF610_ADC_SAMPLE_8,
VF610_ADC_SAMPLE_16,
VF610_ADC_SAMPLE_32,
};
struct vf610_adc_feature {
enum clk_sel clk_sel;
enum vol_ref vol_ref;
int clk_div;
int sample_rate;
int res_mode;
bool lpm;
bool calibration;
bool ovwren;
};
struct vf610_adc {
struct device *dev;
void __iomem *regs;
struct clk *clk;
u32 vref_uv;
u32 value;
struct regulator *vref;
struct vf610_adc_feature adc_feature;
u32 sample_freq_avail[5];
struct completion completion;
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
#define VF610_ADC_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.indexed = 1, \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(0, IIO_VOLTAGE),
VF610_ADC_CHAN(1, IIO_VOLTAGE),
VF610_ADC_CHAN(2, IIO_VOLTAGE),
VF610_ADC_CHAN(3, IIO_VOLTAGE),
VF610_ADC_CHAN(4, IIO_VOLTAGE),
VF610_ADC_CHAN(5, IIO_VOLTAGE),
VF610_ADC_CHAN(6, IIO_VOLTAGE),
VF610_ADC_CHAN(7, IIO_VOLTAGE),
VF610_ADC_CHAN(8, IIO_VOLTAGE),
VF610_ADC_CHAN(9, IIO_VOLTAGE),
VF610_ADC_CHAN(10, IIO_VOLTAGE),
VF610_ADC_CHAN(11, IIO_VOLTAGE),
VF610_ADC_CHAN(12, IIO_VOLTAGE),
VF610_ADC_CHAN(13, IIO_VOLTAGE),
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
/* sentinel */
};
static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
int i;
/*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
* which is the same as bus clock.
*
* ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
* SFCAdder: fixed to 6 ADCK cycles
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
* LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
*/
adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
}
static inline void vf610_adc_cfg_init(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
/* set default Configuration for ADC controller */
adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET;
adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET;
adc_feature->calibration = true;
adc_feature->ovwren = true;
adc_feature->res_mode = 12;
adc_feature->sample_rate = 1;
adc_feature->lpm = true;
/* Use a save ADCK which is below 20MHz on all devices */
adc_feature->clk_div = 8;
vf610_adc_calculate_rates(info);
}
static void vf610_adc_cfg_post_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
int cfg_data = 0;
int gc_data = 0;
switch (adc_feature->clk_sel) {
case VF610_ADCIOC_ALTCLK_SET:
cfg_data |= VF610_ADC_ALTCLK_SEL;
break;
case VF610_ADCIOC_ADACK_SET:
cfg_data |= VF610_ADC_ADACK_SEL;
break;
default:
break;
}
/* low power set for calibration */
cfg_data |= VF610_ADC_ADLPC_EN;
/* enable high speed for calibration */
cfg_data |= VF610_ADC_ADHSC_EN;
/* voltage reference */
switch (adc_feature->vol_ref) {
case VF610_ADCIOC_VR_VREF_SET:
break;
case VF610_ADCIOC_VR_VALT_SET:
cfg_data |= VF610_ADC_REFSEL_VALT;
break;
case VF610_ADCIOC_VR_VBG_SET:
cfg_data |= VF610_ADC_REFSEL_VBG;
break;
default:
dev_err(info->dev, "error voltage reference\n");
}
/* data overwrite enable */
if (adc_feature->ovwren)
cfg_data |= VF610_ADC_OVWREN;
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
writel(gc_data, info->regs + VF610_REG_ADC_GC);
}
static void vf610_adc_calibration(struct vf610_adc *info)
{
int adc_gc, hc_cfg;
int timeout;
if (!info->adc_feature.calibration)
return;
/* enable calibration interrupt */
hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
adc_gc = readl(info->regs + VF610_REG_ADC_GC);
writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
timeout = wait_for_completion_timeout
(&info->completion, VF610_ADC_TIMEOUT);
if (timeout == 0)
dev_err(info->dev, "Timeout for adc calibration\n");
adc_gc = readl(info->regs + VF610_REG_ADC_GS);
if (adc_gc & VF610_ADC_CALF)
dev_err(info->dev, "ADC calibration failed\n");
info->adc_feature.calibration = false;
}
static void vf610_adc_cfg_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &(info->adc_feature);
int cfg_data;
cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
cfg_data &= ~VF610_ADC_ADLPC_EN;
if (adc_feature->lpm)
cfg_data |= VF610_ADC_ADLPC_EN;
cfg_data &= ~VF610_ADC_ADHSC_EN;
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
}
static void vf610_adc_sample_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &(info->adc_feature);
int cfg_data, gc_data;
cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
gc_data = readl(info->regs + VF610_REG_ADC_GC);
/* resolution mode */
cfg_data &= ~VF610_ADC_MODE_MASK;
switch (adc_feature->res_mode) {
case 8:
cfg_data |= VF610_ADC_MODE_BIT8;
break;
case 10:
cfg_data |= VF610_ADC_MODE_BIT10;
break;
case 12:
cfg_data |= VF610_ADC_MODE_BIT12;
break;
default:
dev_err(info->dev, "error resolution mode\n");
break;
}
/* clock select and clock divider */
cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK);
switch (adc_feature->clk_div) {
case 1:
break;
case 2:
cfg_data |= VF610_ADC_CLK_DIV2;
break;
case 4:
cfg_data |= VF610_ADC_CLK_DIV4;
break;
case 8:
cfg_data |= VF610_ADC_CLK_DIV8;
break;
case 16:
switch (adc_feature->clk_sel) {
case VF610_ADCIOC_BUSCLK_SET:
cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8;
break;
default:
dev_err(info->dev, "error clk divider\n");
break;
}
break;
}
/* Use the short sample mode */
cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
/* update hardware average selection */
cfg_data &= ~VF610_ADC_AVGS_MASK;
gc_data &= ~VF610_ADC_AVGEN;
switch (adc_feature->sample_rate) {
case VF610_ADC_SAMPLE_1:
break;
case VF610_ADC_SAMPLE_4:
gc_data |= VF610_ADC_AVGEN;
break;
case VF610_ADC_SAMPLE_8:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_8;
break;
case VF610_ADC_SAMPLE_16:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_16;
break;
case VF610_ADC_SAMPLE_32:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_32;
break;
default:
dev_err(info->dev,
"error hardware sample average select\n");
}
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
writel(gc_data, info->regs + VF610_REG_ADC_GC);
}
static void vf610_adc_hw_init(struct vf610_adc *info)
{
/* CFG: Feature set */
vf610_adc_cfg_post_set(info);
vf610_adc_sample_set(info);
/* adc calibration */
vf610_adc_calibration(info);
/* CFG: power and speed set */
vf610_adc_cfg_set(info);
}
static int vf610_adc_read_data(struct vf610_adc *info)
{
int result;
result = readl(info->regs + VF610_REG_ADC_R0);
switch (info->adc_feature.res_mode) {
case 8:
result &= 0xFF;
break;
case 10:
result &= 0x3FF;
break;
case 12:
result &= 0xFFF;
break;
default:
break;
}
return result;
}
static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
{
struct vf610_adc *info = (struct vf610_adc *)dev_id;
int coco;
coco = readl(info->regs + VF610_REG_ADC_HS);
if (coco & VF610_ADC_HS_COCO0) {
info->value = vf610_adc_read_data(info);
complete(&info->completion);
}
return IRQ_HANDLED;
}
static ssize_t vf610_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev));
size_t len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%u ", info->sample_freq_avail[i]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail);
static struct attribute *vf610_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group vf610_attribute_group = {
.attrs = vf610_attributes,
};
static int vf610_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
unsigned int hc_cfg;
long ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
hc_cfg = VF610_ADC_ADCHC(chan->channel);
hc_cfg |= VF610_ADC_AIEN;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
ret = wait_for_completion_interruptible_timeout
(&info->completion, VF610_ADC_TIMEOUT);
if (ret == 0) {
mutex_unlock(&indio_dev->mlock);
return -ETIMEDOUT;
}
if (ret < 0) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
*val = info->value;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = info->vref_uv / 1000;
*val2 = info->adc_feature.res_mode;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = info->sample_freq_avail[info->adc_feature.sample_rate];
*val2 = 0;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int vf610_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
int i;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0;
i < ARRAY_SIZE(info->sample_freq_avail);
i++)
if (val == info->sample_freq_avail[i]) {
info->adc_feature.sample_rate = i;
vf610_adc_sample_set(info);
return 0;
}
break;
default:
break;
}
return -EINVAL;
}
static int vf610_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct vf610_adc *info = iio_priv(indio_dev);
if ((readval == NULL) ||
(!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
return -EINVAL;
*readval = readl(info->regs + reg);
return 0;
}
static const struct iio_info vf610_adc_iio_info = {
.driver_module = THIS_MODULE,
.read_raw = &vf610_read_raw,
.write_raw = &vf610_write_raw,
.debugfs_reg_access = &vf610_adc_reg_access,
.attrs = &vf610_attribute_group,
};
static const struct of_device_id vf610_adc_match[] = {
{ .compatible = "fsl,vf610-adc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, vf610_adc_match);
static int vf610_adc_probe(struct platform_device *pdev)
{
struct vf610_adc *info;
struct iio_dev *indio_dev;
struct resource *mem;
int irq;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "Failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return -EINVAL;
}
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,
dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
return ret;
}
info->clk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
ret = PTR_ERR(info->clk);
return ret;
}
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref))
return PTR_ERR(info->vref);
ret = regulator_enable(info->vref);
if (ret)
return ret;
info->vref_uv = regulator_get_voltage(info->vref);
platform_set_drvdata(pdev, indio_dev);
init_completion(&info->completion);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &vf610_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vf610_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev,
"Could not prepare or enable the clock.\n");
goto error_adc_clk_enable;
}
vf610_adc_cfg_init(info);
vf610_adc_hw_init(info);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto error_iio_device_register;
}
return 0;
error_iio_device_register:
clk_disable_unprepare(info->clk);
error_adc_clk_enable:
regulator_disable(info->vref);
return ret;
}
static int vf610_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int vf610_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct vf610_adc *info = iio_priv(indio_dev);
int hc_cfg;
/* ADC controller enters to stop mode */
hc_cfg = readl(info->regs + VF610_REG_ADC_HC0);
hc_cfg |= VF610_ADC_CONV_DISABLE;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
clk_disable_unprepare(info->clk);
regulator_disable(info->vref);
return 0;
}
static int vf610_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct vf610_adc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vref);
if (ret)
return ret;
ret = clk_prepare_enable(info->clk);
if (ret)
return ret;
vf610_adc_hw_init(info);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
vf610_adc_suspend,
vf610_adc_resume);
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
.remove = vf610_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = vf610_adc_match,
.pm = &vf610_adc_pm_ops,
},
};
module_platform_driver(vf610_adc_driver);
MODULE_AUTHOR("Fugang Duan <B38611@freescale.com>");
MODULE_DESCRIPTION("Freescale VF610 ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,157 @@
/*
* Nano River Technologies viperboard IIO ADC driver
*
* (C) 2012 by Lemonage GmbH
* Author: Lars Poeschel <poeschel@lemonage.de>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/iio/iio.h>
#include <linux/mfd/viperboard.h>
#define VPRBRD_ADC_CMD_GET 0x00
struct vprbrd_adc_msg {
u8 cmd;
u8 chan;
u8 val;
} __packed;
struct vprbrd_adc {
struct vprbrd *vb;
};
#define VPRBRD_ADC_CHANNEL(_index) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static struct iio_chan_spec const vprbrd_adc_iio_channels[] = {
VPRBRD_ADC_CHANNEL(0),
VPRBRD_ADC_CHANNEL(1),
VPRBRD_ADC_CHANNEL(2),
VPRBRD_ADC_CHANNEL(3),
};
static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
int ret, error = 0;
struct vprbrd_adc *adc = iio_priv(iio_dev);
struct vprbrd *vb = adc->vb;
struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf;
switch (info) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&vb->lock);
admsg->cmd = VPRBRD_ADC_CMD_GET;
admsg->chan = chan->channel;
admsg->val = 0x00;
ret = usb_control_msg(vb->usb_dev,
usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
if (ret != sizeof(struct vprbrd_adc_msg)) {
dev_err(&iio_dev->dev, "usb send error on adc read\n");
error = -EREMOTEIO;
}
ret = usb_control_msg(vb->usb_dev,
usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
*val = admsg->val;
mutex_unlock(&vb->lock);
if (ret != sizeof(struct vprbrd_adc_msg)) {
dev_err(&iio_dev->dev, "usb recv error on adc read\n");
error = -EREMOTEIO;
}
if (error)
goto error;
return IIO_VAL_INT;
default:
error = -EINVAL;
break;
}
error:
return error;
}
static const struct iio_info vprbrd_adc_iio_info = {
.read_raw = &vprbrd_iio_read_raw,
.driver_module = THIS_MODULE,
};
static int vprbrd_adc_probe(struct platform_device *pdev)
{
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
struct vprbrd_adc *adc;
struct iio_dev *indio_dev;
int ret;
/* registering iio */
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
adc = iio_priv(indio_dev);
adc->vb = vb;
indio_dev->name = "viperboard adc";
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &vprbrd_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vprbrd_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels);
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio (adc)");
return ret;
}
return 0;
}
static struct platform_driver vprbrd_adc_driver = {
.driver = {
.name = "viperboard-adc",
},
.probe = vprbrd_adc_probe,
};
module_platform_driver(vprbrd_adc_driver);
MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:viperboard-adc");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,248 @@
/*
* Xilinx XADC driver
*
* Copyright 2013 Analog Devices Inc.
* Author: Lars-Peter Clauen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include "xilinx-xadc.h"
static const struct iio_chan_spec *xadc_event_to_channel(
struct iio_dev *indio_dev, unsigned int event)
{
switch (event) {
case XADC_THRESHOLD_OT_MAX:
case XADC_THRESHOLD_TEMP_MAX:
return &indio_dev->channels[0];
case XADC_THRESHOLD_VCCINT_MAX:
case XADC_THRESHOLD_VCCAUX_MAX:
return &indio_dev->channels[event];
default:
return &indio_dev->channels[event-1];
}
}
static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
{
const struct iio_chan_spec *chan;
/* Temperature threshold error, we don't handle this yet */
if (event == 0)
return;
chan = xadc_event_to_channel(indio_dev, event);
if (chan->type == IIO_TEMP) {
/*
* The temperature channel only supports over-temperature
* events.
*/
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
iio_get_time_ns());
} else {
/*
* For other channels we don't know whether it is a upper or
* lower threshold event. Userspace will have to check the
* channel value if it wants to know.
*/
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
iio_get_time_ns());
}
}
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
{
unsigned int i;
for_each_set_bit(i, &events, 8)
xadc_handle_event(indio_dev, i);
}
static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
enum iio_event_direction dir)
{
unsigned int offset;
if (chan->type == IIO_TEMP) {
offset = XADC_THRESHOLD_OT_MAX;
} else {
if (chan->channel < 2)
offset = chan->channel + 1;
else
offset = chan->channel + 6;
}
if (dir == IIO_EV_DIR_FALLING)
offset += 4;
return offset;
}
static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
{
if (chan->type == IIO_TEMP) {
return XADC_ALARM_OT_MASK;
} else {
switch (chan->channel) {
case 0:
return XADC_ALARM_VCCINT_MASK;
case 1:
return XADC_ALARM_VCCAUX_MASK;
case 2:
return XADC_ALARM_VCCBRAM_MASK;
case 3:
return XADC_ALARM_VCCPINT_MASK;
case 4:
return XADC_ALARM_VCCPAUX_MASK;
case 5:
return XADC_ALARM_VCCODDR_MASK;
default:
/* We will never get here */
return 0;
}
}
}
int xadc_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir)
{
struct xadc *xadc = iio_priv(indio_dev);
return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
}
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
unsigned int alarm = xadc_get_alarm_mask(chan);
struct xadc *xadc = iio_priv(indio_dev);
uint16_t cfg, old_cfg;
int ret;
mutex_lock(&xadc->mutex);
if (state)
xadc->alarm_mask |= alarm;
else
xadc->alarm_mask &= ~alarm;
xadc->ops->update_alarm(xadc, xadc->alarm_mask);
ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
if (ret)
goto err_out;
old_cfg = cfg;
cfg |= XADC_CONF1_ALARM_MASK;
cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
if (old_cfg != cfg)
ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
err_out:
mutex_unlock(&xadc->mutex);
return ret;
}
/* Register value is msb aligned, the lower 4 bits are ignored */
#define XADC_THRESHOLD_VALUE_SHIFT 4
int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2)
{
unsigned int offset = xadc_get_threshold_offset(chan, dir);
struct xadc *xadc = iio_priv(indio_dev);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = xadc->threshold[offset];
break;
case IIO_EV_INFO_HYSTERESIS:
*val = xadc->temp_hysteresis;
break;
default:
return -EINVAL;
}
*val >>= XADC_THRESHOLD_VALUE_SHIFT;
return IIO_VAL_INT;
}
int xadc_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2)
{
unsigned int offset = xadc_get_threshold_offset(chan, dir);
struct xadc *xadc = iio_priv(indio_dev);
int ret = 0;
val <<= XADC_THRESHOLD_VALUE_SHIFT;
if (val < 0 || val > 0xffff)
return -EINVAL;
mutex_lock(&xadc->mutex);
switch (info) {
case IIO_EV_INFO_VALUE:
xadc->threshold[offset] = val;
break;
case IIO_EV_INFO_HYSTERESIS:
xadc->temp_hysteresis = val;
break;
default:
mutex_unlock(&xadc->mutex);
return -EINVAL;
}
if (chan->type == IIO_TEMP) {
/*
* According to the datasheet we need to set the lower 4 bits to
* 0x3, otherwise 125 degree celsius will be used as the
* threshold.
*/
val |= 0x3;
/*
* Since we store the hysteresis as relative (to the threshold)
* value, but the hardware expects an absolute value we need to
* recalcualte this value whenever the hysteresis or the
* threshold changes.
*/
if (xadc->threshold[offset] < xadc->temp_hysteresis)
xadc->threshold[offset + 4] = 0;
else
xadc->threshold[offset + 4] = xadc->threshold[offset] -
xadc->temp_hysteresis;
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
xadc->threshold[offset + 4]);
if (ret)
goto out_unlock;
}
if (info == IIO_EV_INFO_VALUE)
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
out_unlock:
mutex_unlock(&xadc->mutex);
return ret;
}

View file

@ -0,0 +1,209 @@
/*
* Xilinx XADC driver
*
* Copyright 2013 Analog Devices Inc.
* Author: Lars-Peter Clauen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#ifndef __IIO_XILINX_XADC__
#define __IIO_XILINX_XADC__
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
struct iio_dev;
struct clk;
struct xadc_ops;
struct platform_device;
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events);
int xadc_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir);
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state);
int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2);
int xadc_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2);
enum xadc_external_mux_mode {
XADC_EXTERNAL_MUX_NONE,
XADC_EXTERNAL_MUX_SINGLE,
XADC_EXTERNAL_MUX_DUAL,
};
struct xadc {
void __iomem *base;
struct clk *clk;
const struct xadc_ops *ops;
uint16_t threshold[16];
uint16_t temp_hysteresis;
unsigned int alarm_mask;
uint16_t *data;
struct iio_trigger *trigger;
struct iio_trigger *convst_trigger;
struct iio_trigger *samplerate_trigger;
enum xadc_external_mux_mode external_mux_mode;
unsigned int zynq_alarm;
unsigned int zynq_masked_alarm;
unsigned int zynq_intmask;
struct delayed_work zynq_unmask_work;
struct mutex mutex;
spinlock_t lock;
struct completion completion;
};
struct xadc_ops {
int (*read)(struct xadc *, unsigned int, uint16_t *);
int (*write)(struct xadc *, unsigned int, uint16_t);
int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
int irq);
void (*update_alarm)(struct xadc *, unsigned int);
unsigned long (*get_dclk_rate)(struct xadc *);
irqreturn_t (*interrupt_handler)(int, void *);
irqreturn_t (*threaded_interrupt_handler)(int, void *);
unsigned int flags;
};
static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t *val)
{
lockdep_assert_held(&xadc->mutex);
return xadc->ops->read(xadc, reg, val);
}
static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t val)
{
lockdep_assert_held(&xadc->mutex);
return xadc->ops->write(xadc, reg, val);
}
static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t *val)
{
int ret;
mutex_lock(&xadc->mutex);
ret = _xadc_read_adc_reg(xadc, reg, val);
mutex_unlock(&xadc->mutex);
return ret;
}
static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t val)
{
int ret;
mutex_lock(&xadc->mutex);
ret = _xadc_write_adc_reg(xadc, reg, val);
mutex_unlock(&xadc->mutex);
return ret;
}
/* XADC hardmacro register definitions */
#define XADC_REG_TEMP 0x00
#define XADC_REG_VCCINT 0x01
#define XADC_REG_VCCAUX 0x02
#define XADC_REG_VPVN 0x03
#define XADC_REG_VREFP 0x04
#define XADC_REG_VREFN 0x05
#define XADC_REG_VCCBRAM 0x06
#define XADC_REG_VCCPINT 0x0d
#define XADC_REG_VCCPAUX 0x0e
#define XADC_REG_VCCO_DDR 0x0f
#define XADC_REG_VAUX(x) (0x10 + (x))
#define XADC_REG_MAX_TEMP 0x20
#define XADC_REG_MAX_VCCINT 0x21
#define XADC_REG_MAX_VCCAUX 0x22
#define XADC_REG_MAX_VCCBRAM 0x23
#define XADC_REG_MIN_TEMP 0x24
#define XADC_REG_MIN_VCCINT 0x25
#define XADC_REG_MIN_VCCAUX 0x26
#define XADC_REG_MIN_VCCBRAM 0x27
#define XADC_REG_MAX_VCCPINT 0x28
#define XADC_REG_MAX_VCCPAUX 0x29
#define XADC_REG_MAX_VCCO_DDR 0x2a
#define XADC_REG_MIN_VCCPINT 0x2b
#define XADC_REG_MIN_VCCPAUX 0x2c
#define XADC_REG_MIN_VCCO_DDR 0x2d
#define XADC_REG_CONF0 0x40
#define XADC_REG_CONF1 0x41
#define XADC_REG_CONF2 0x42
#define XADC_REG_SEQ(x) (0x48 + (x))
#define XADC_REG_INPUT_MODE(x) (0x4c + (x))
#define XADC_REG_THRESHOLD(x) (0x50 + (x))
#define XADC_REG_FLAG 0x3f
#define XADC_CONF0_EC BIT(9)
#define XADC_CONF0_ACQ BIT(8)
#define XADC_CONF0_MUX BIT(11)
#define XADC_CONF0_CHAN(x) (x)
#define XADC_CONF1_SEQ_MASK (0xf << 12)
#define XADC_CONF1_SEQ_DEFAULT (0 << 12)
#define XADC_CONF1_SEQ_SINGLE_PASS (1 << 12)
#define XADC_CONF1_SEQ_CONTINUOUS (2 << 12)
#define XADC_CONF1_SEQ_SINGLE_CHANNEL (3 << 12)
#define XADC_CONF1_SEQ_SIMULTANEOUS (4 << 12)
#define XADC_CONF1_SEQ_INDEPENDENT (8 << 12)
#define XADC_CONF1_ALARM_MASK 0x0f0f
#define XADC_CONF2_DIV_MASK 0xff00
#define XADC_CONF2_DIV_OFFSET 8
#define XADC_CONF2_PD_MASK (0x3 << 4)
#define XADC_CONF2_PD_NONE (0x0 << 4)
#define XADC_CONF2_PD_ADC_B (0x2 << 4)
#define XADC_CONF2_PD_BOTH (0x3 << 4)
#define XADC_ALARM_TEMP_MASK BIT(0)
#define XADC_ALARM_VCCINT_MASK BIT(1)
#define XADC_ALARM_VCCAUX_MASK BIT(2)
#define XADC_ALARM_OT_MASK BIT(3)
#define XADC_ALARM_VCCBRAM_MASK BIT(4)
#define XADC_ALARM_VCCPINT_MASK BIT(5)
#define XADC_ALARM_VCCPAUX_MASK BIT(6)
#define XADC_ALARM_VCCODDR_MASK BIT(7)
#define XADC_THRESHOLD_TEMP_MAX 0x0
#define XADC_THRESHOLD_VCCINT_MAX 0x1
#define XADC_THRESHOLD_VCCAUX_MAX 0x2
#define XADC_THRESHOLD_OT_MAX 0x3
#define XADC_THRESHOLD_TEMP_MIN 0x4
#define XADC_THRESHOLD_VCCINT_MIN 0x5
#define XADC_THRESHOLD_VCCAUX_MIN 0x6
#define XADC_THRESHOLD_OT_MIN 0x7
#define XADC_THRESHOLD_VCCBRAM_MAX 0x8
#define XADC_THRESHOLD_VCCPINT_MAX 0x9
#define XADC_THRESHOLD_VCCPAUX_MAX 0xa
#define XADC_THRESHOLD_VCCODDR_MAX 0xb
#define XADC_THRESHOLD_VCCBRAM_MIN 0xc
#define XADC_THRESHOLD_VCCPINT_MIN 0xd
#define XADC_THRESHOLD_VCCPAUX_MIN 0xe
#define XADC_THRESHOLD_VCCODDR_MIN 0xf
#endif

View file

@ -0,0 +1,19 @@
#
# Gain Amplifiers, etc.
#
# When adding new entries keep the list in alphabetical order
menu "Amplifiers"
config AD8366
tristate "Analog Devices AD8366 VGA"
depends on SPI
select BITREVERSE
help
Say yes here to build support for Analog Devices AD8366
SPI Dual-Digital Variable Gain Amplifier (VGA).
To compile this driver as a module, choose M here: the
module will be called ad8366.
endmenu

View file

@ -0,0 +1,6 @@
#
# Makefile iio/amplifiers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD8366) += ad8366.o

View file

@ -0,0 +1,213 @@
/*
* AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/bitrev.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
struct ad8366_state {
struct spi_device *spi;
struct regulator *reg;
unsigned char ch[2];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned char data[2] ____cacheline_aligned;
};
static int ad8366_write(struct iio_dev *indio_dev,
unsigned char ch_a, char unsigned ch_b)
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
ch_a = bitrev8(ch_a & 0x3F);
ch_b = bitrev8(ch_b & 0x3F);
st->data[0] = ch_b >> 4;
st->data[1] = (ch_b << 4) | (ch_a >> 2);
ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
if (ret < 0)
dev_err(&indio_dev->dev, "write failed (%d)", ret);
return ret;
}
static int ad8366_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
unsigned code;
mutex_lock(&indio_dev->mlock);
switch (m) {
case IIO_CHAN_INFO_HARDWAREGAIN:
code = st->ch[chan->channel];
/* Values in dB */
code = code * 253 + 4500;
*val = code / 1000;
*val2 = (code % 1000) * 1000;
ret = IIO_VAL_INT_PLUS_MICRO_DB;
break;
default:
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return ret;
};
static int ad8366_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad8366_state *st = iio_priv(indio_dev);
unsigned code;
int ret;
if (val < 0 || val2 < 0)
return -EINVAL;
/* Values in dB */
code = (((u8)val * 1000) + ((u32)val2 / 1000));
if (code > 20500 || code < 4500)
return -EINVAL;
code = (code - 4500) / 253;
mutex_lock(&indio_dev->mlock);
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
st->ch[chan->channel] = code;
ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return ret;
}
static const struct iio_info ad8366_info = {
.read_raw = &ad8366_read_raw,
.write_raw = &ad8366_write_raw,
.driver_module = THIS_MODULE,
};
#define AD8366_CHAN(_channel) { \
.type = IIO_VOLTAGE, \
.output = 1, \
.indexed = 1, \
.channel = _channel, \
.info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
}
static const struct iio_chan_spec ad8366_channels[] = {
AD8366_CHAN(0),
AD8366_CHAN(1),
};
static int ad8366_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad8366_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad8366_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad8366_channels;
indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
ad8366_write(indio_dev, 0 , 0);
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static int ad8366_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad8366_state *st = iio_priv(indio_dev);
struct regulator *reg = st->reg;
iio_device_unregister(indio_dev);
if (!IS_ERR(reg))
regulator_disable(reg);
return 0;
}
static const struct spi_device_id ad8366_id[] = {
{"ad8366", 0},
{}
};
static struct spi_driver ad8366_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
.probe = ad8366_probe,
.remove = ad8366_remove,
.id_table = ad8366_id,
};
module_spi_driver(ad8366_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
MODULE_LICENSE("GPL v2");

124
drivers/iio/buffer_cb.c Normal file
View file

@ -0,0 +1,124 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/iio/buffer.h>
#include <linux/iio/consumer.h>
struct iio_cb_buffer {
struct iio_buffer buffer;
int (*cb)(const void *data, void *private);
void *private;
struct iio_channel *channels;
};
static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
{
return container_of(buffer, struct iio_cb_buffer, buffer);
}
static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
{
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
return cb_buff->cb(data, cb_buff->private);
}
static void iio_buffer_cb_release(struct iio_buffer *buffer)
{
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
kfree(cb_buff->buffer.scan_mask);
kfree(cb_buff);
}
static const struct iio_buffer_access_funcs iio_cb_access = {
.store_to = &iio_buffer_cb_store_to,
.release = &iio_buffer_cb_release,
};
struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
int (*cb)(const void *data,
void *private),
void *private)
{
int ret;
struct iio_cb_buffer *cb_buff;
struct iio_dev *indio_dev;
struct iio_channel *chan;
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
if (cb_buff == NULL)
return ERR_PTR(-ENOMEM);
iio_buffer_init(&cb_buff->buffer);
cb_buff->private = private;
cb_buff->cb = cb;
cb_buff->buffer.access = &iio_cb_access;
INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
cb_buff->channels = iio_channel_get_all(dev);
if (IS_ERR(cb_buff->channels)) {
ret = PTR_ERR(cb_buff->channels);
goto error_free_cb_buff;
}
indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->buffer.scan_mask
= kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
GFP_KERNEL);
if (cb_buff->buffer.scan_mask == NULL) {
ret = -ENOMEM;
goto error_release_channels;
}
chan = &cb_buff->channels[0];
while (chan->indio_dev) {
if (chan->indio_dev != indio_dev) {
ret = -EINVAL;
goto error_free_scan_mask;
}
set_bit(chan->channel->scan_index,
cb_buff->buffer.scan_mask);
chan++;
}
return cb_buff;
error_free_scan_mask:
kfree(cb_buff->buffer.scan_mask);
error_release_channels:
iio_channel_release_all(cb_buff->channels);
error_free_cb_buff:
kfree(cb_buff);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
{
return iio_update_buffers(cb_buff->channels[0].indio_dev,
&cb_buff->buffer,
NULL);
}
EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
{
iio_update_buffers(cb_buff->channels[0].indio_dev,
NULL,
&cb_buff->buffer);
}
EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
{
iio_channel_release_all(cb_buff->channels);
iio_buffer_put(&cb_buff->buffer);
}
EXPORT_SYMBOL_GPL(iio_channel_release_all_cb);
struct iio_channel
*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer)
{
return cb_buffer->channels;
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);

View file

@ -0,0 +1,6 @@
#
# IIO common modules
#
source "drivers/iio/common/hid-sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"

View file

@ -0,0 +1,11 @@
#
# Makefile for the IIO common modules.
# Common modules contains modules, which can be shared among multiple
# IIO modules. For example if the trigger processing is common for
# multiple IIO modules then this can be moved to a common module
# instead of duplicating in each module.
#
# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
obj-y += st_sensors/

View file

@ -0,0 +1,28 @@
#
# Hid Sensor common modules
#
menu "Hid Sensor IIO Common"
config HID_SENSOR_IIO_COMMON
tristate "Common modules for all HID Sensor IIO drivers"
depends on HID_SENSOR_HUB
select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER
help
Say yes here to build support for HID sensor to use
HID sensor common processing for attributes and IIO triggers.
There are many attributes which can be shared among multiple
HID sensor drivers, this module contains processing for those
attributes.
config HID_SENSOR_IIO_TRIGGER
tristate "Common module (trigger) for all HID Sensor IIO drivers"
depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON
select IIO_TRIGGER
help
Say yes here to build trigger support for HID sensors.
Triggers will be send if all requested attributes were read.
If this driver is compiled as a module, it will be named
hid-sensor-trigger.
endmenu

View file

@ -0,0 +1,7 @@
#
# Makefile for the Hid sensor common modules.
#
obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
obj-$(CONFIG_HID_SENSOR_IIO_TRIGGER) += hid-sensor-trigger.o
hid-sensor-iio-common-y := hid-sensor-attributes.o

View file

@ -0,0 +1,397 @@
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
static struct {
u32 usage_id;
int unit; /* 0 for default others from HID sensor spec */
int scale_val0; /* scale, whole number */
int scale_val1; /* scale, fraction in micros */
} unit_conversion[] = {
{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
{HID_USAGE_SENSOR_ACCEL_3D,
HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
{HID_USAGE_SENSOR_ACCEL_3D,
HID_USAGE_SENSOR_UNITS_G, 9, 806650},
{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453},
{HID_USAGE_SENSOR_GYRO_3D,
HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
{HID_USAGE_SENSOR_GYRO_3D,
HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453},
{HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000},
{HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
{HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453},
{HID_USAGE_SENSOR_INCLINOMETER_3D,
HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453},
{HID_USAGE_SENSOR_INCLINOMETER_3D,
HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
{HID_USAGE_SENSOR_ALS, 0, 1, 0},
{HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
{HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0},
{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0},
};
static int pow_10(unsigned power)
{
int i;
int ret = 1;
for (i = 0; i < power; ++i)
ret = ret * 10;
return ret;
}
static void simple_div(int dividend, int divisor, int *whole,
int *micro_frac)
{
int rem;
int exp = 0;
*micro_frac = 0;
if (divisor == 0) {
*whole = 0;
return;
}
*whole = dividend/divisor;
rem = dividend % divisor;
if (rem) {
while (rem <= divisor) {
rem *= 10;
exp++;
}
*micro_frac = (rem / divisor) * pow_10(6-exp);
}
}
static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
{
*val1 = no/pow_10(exp);
*val2 = no%pow_10(exp) * pow_10(6-exp);
}
/*
VTF format uses exponent and variable size format.
For example if the size is 2 bytes
0x0067 with VTF16E14 format -> +1.03
To convert just change to 0x67 to decimal and use two decimal as E14 stands
for 10^-2.
Negative numbers are 2's complement
*/
static void convert_from_vtf_format(u32 value, int size, int exp,
int *val1, int *val2)
{
int sign = 1;
if (value & BIT(size*8 - 1)) {
value = ((1LL << (size * 8)) - value);
sign = -1;
}
exp = hid_sensor_convert_exponent(exp);
if (exp >= 0) {
*val1 = sign * value * pow_10(exp);
*val2 = 0;
} else {
split_micro_fraction(value, -exp, val1, val2);
if (*val1)
*val1 = sign * (*val1);
else
*val2 = sign * (*val2);
}
}
static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
{
u32 value;
int sign = 1;
if (val1 < 0 || val2 < 0)
sign = -1;
exp = hid_sensor_convert_exponent(exp);
if (exp < 0) {
value = abs(val1) * pow_10(-exp);
value += abs(val2) / pow_10(6+exp);
} else
value = abs(val1) / pow_10(exp);
if (sign < 0)
value = ((1LL << (size * 8)) - value);
return value;
}
s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
{
s32 value = 0;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id,
st->poll.index, &value);
if (ret < 0 || value < 0) {
return -EINVAL;
} else {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
value = value * 1000;
}
return value;
}
EXPORT_SYMBOL(hid_sensor_read_poll_value);
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id,
st->poll.index, &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
} else {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
simple_div(1000, value, val1, val2);
else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
simple_div(1, value, val1, val2);
else {
*val1 = *val2 = 0;
return -EINVAL;
}
}
return IIO_VAL_INT_PLUS_MICRO;
}
EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
int val1, int val2)
{
s32 value;
int ret;
if (val1 < 0 || val2 < 0)
ret = -EINVAL;
value = val1 * pow_10(6) + val2;
if (value) {
if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
value = pow_10(9)/value;
else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
value = pow_10(6)/value;
else
value = 0;
}
ret = sensor_hub_set_feature(st->hsdev,
st->poll.report_id,
st->poll.index, value);
if (ret < 0 || value < 0)
ret = -EINVAL;
return ret;
}
EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
st->sensitivity.index, &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
} else {
convert_from_vtf_format(value, st->sensitivity.size,
st->sensitivity.unit_expo,
val1, val2);
}
return IIO_VAL_INT_PLUS_MICRO;
}
EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
int val1, int val2)
{
s32 value;
int ret;
value = convert_to_vtf_format(st->sensitivity.size,
st->sensitivity.unit_expo,
val1, val2);
ret = sensor_hub_set_feature(st->hsdev,
st->sensitivity.report_id,
st->sensitivity.index, value);
if (ret < 0 || value < 0)
ret = -EINVAL;
return ret;
}
EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
/*
* This fuction applies the unit exponent to the scale.
* For example:
* 9.806650 ->exp:2-> val0[980]val1[665000]
* 9.000806 ->exp:2-> val0[900]val1[80600]
* 0.174535 ->exp:2-> val0[17]val1[453500]
* 1.001745 ->exp:0-> val0[1]val1[1745]
* 1.001745 ->exp:2-> val0[100]val1[174500]
* 1.001745 ->exp:4-> val0[10017]val1[450000]
* 9.806650 ->exp:-2-> val0[0]val1[98066]
*/
static void adjust_exponent_micro(int *val0, int *val1, int scale0,
int scale1, int exp)
{
int i;
int x;
int res;
int rem;
if (exp > 0) {
*val0 = scale0 * pow_10(exp);
res = 0;
if (exp > 6) {
*val1 = 0;
return;
}
for (i = 0; i < exp; ++i) {
x = scale1 / pow_10(5 - i);
res += (pow_10(exp - 1 - i) * x);
scale1 = scale1 % pow_10(5 - i);
}
*val0 += res;
*val1 = scale1 * pow_10(exp);
} else if (exp < 0) {
exp = abs(exp);
if (exp > 6) {
*val0 = *val1 = 0;
return;
}
*val0 = scale0 / pow_10(exp);
rem = scale0 % pow_10(exp);
res = 0;
for (i = 0; i < (6 - exp); ++i) {
x = scale1 / pow_10(5 - i);
res += (pow_10(5 - exp - i) * x);
scale1 = scale1 % pow_10(5 - i);
}
*val1 = rem * pow_10(6 - exp) + res;
} else {
*val0 = scale0;
*val1 = scale1;
}
}
int hid_sensor_format_scale(u32 usage_id,
struct hid_sensor_hub_attribute_info *attr_info,
int *val0, int *val1)
{
int i;
int exp;
*val0 = 1;
*val1 = 0;
for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
if (unit_conversion[i].usage_id == usage_id &&
unit_conversion[i].unit == attr_info->units) {
exp = hid_sensor_convert_exponent(
attr_info->unit_expo);
adjust_exponent_micro(val0, val1,
unit_conversion[i].scale_val0,
unit_conversion[i].scale_val1, exp);
break;
}
}
return IIO_VAL_INT_PLUS_MICRO;
}
EXPORT_SYMBOL(hid_sensor_format_scale);
static
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_common *st)
{
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
&st->poll);
/* Default unit of measure is milliseconds */
if (st->poll.units == 0)
st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND;
return 0;
}
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_common *st)
{
hid_sensor_get_reporting_interval(hsdev, usage_id, st);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_REPORT_STATE,
&st->report_state);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROY_POWER_STATE,
&st->power_state);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
&st->sensitivity);
hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
st->poll.index, st->poll.report_id,
st->report_state.index, st->report_state.report_id,
st->power_state.index, st->power_state.report_id,
st->sensitivity.index, st->sensitivity.report_id);
return 0;
}
EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor common attribute processing");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,139 @@
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.h"
int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
{
int state_val;
int report_val;
if (state) {
if (sensor_hub_device_open(st->hsdev))
return -EIO;
atomic_inc(&st->data_ready);
state_val = hid_sensor_get_usage_index(st->hsdev,
st->power_state.report_id,
st->power_state.index,
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM);
report_val = hid_sensor_get_usage_index(st->hsdev,
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
} else {
if (!atomic_dec_and_test(&st->data_ready))
return 0;
sensor_hub_device_close(st->hsdev);
state_val = hid_sensor_get_usage_index(st->hsdev,
st->power_state.report_id,
st->power_state.index,
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM);
report_val = hid_sensor_get_usage_index(st->hsdev,
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
}
if (state_val >= 0) {
state_val += st->power_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
(s32)state_val);
}
if (report_val >= 0) {
report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index,
(s32)report_val);
}
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
&state_val);
return 0;
}
EXPORT_SYMBOL(hid_sensor_power_state);
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
}
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
}
EXPORT_SYMBOL(hid_sensor_remove_trigger);
static const struct iio_trigger_ops hid_sensor_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
};
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb)
{
int ret;
struct iio_trigger *trig;
trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM;
goto error_ret;
}
trig->dev.parent = indio_dev->dev.parent;
iio_trigger_set_drvdata(trig, attrb);
trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
if (ret) {
dev_err(&indio_dev->dev, "Trigger Register Failed\n");
goto error_free_trig;
}
attrb->trigger = trig;
indio_dev->trig = iio_trigger_get(trig);
return ret;
error_free_trig:
iio_trigger_free(trig);
error_ret:
return ret;
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor trigger processing");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,27 @@
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef _HID_SENSOR_TRIGGER_H
#define _HID_SENSOR_TRIGGER_H
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
#endif

View file

@ -0,0 +1,14 @@
#
# STMicroelectronics sensors common library
#
config IIO_ST_SENSORS_I2C
tristate
config IIO_ST_SENSORS_SPI
tristate
config IIO_ST_SENSORS_CORE
tristate
select IIO_ST_SENSORS_I2C if I2C
select IIO_ST_SENSORS_SPI if SPI_MASTER

View file

@ -0,0 +1,10 @@
#
# Makefile for the STMicroelectronics sensor common modules.
#
obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
st_sensors-y := st_sensors_core.o
st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o

View file

@ -0,0 +1,128 @@
/*
* STMicroelectronics sensors buffer library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/irqreturn.h>
#include <linux/iio/common/st_sensors.h>
int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
{
u8 *addr;
int i, n = 0, len;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int num_data_channels = sdata->num_data_channels;
unsigned int byte_for_channel =
indio_dev->channels[0].scan_type.storagebits >> 3;
addr = kmalloc(num_data_channels, GFP_KERNEL);
if (!addr) {
len = -ENOMEM;
goto st_sensors_get_buffer_element_error;
}
for (i = 0; i < num_data_channels; i++) {
if (test_bit(i, indio_dev->active_scan_mask)) {
addr[n] = indio_dev->channels[i].address;
n++;
}
}
switch (n) {
case 1:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], byte_for_channel, buf, sdata->multiread_bit);
break;
case 2:
if ((addr[1] - addr[0]) == byte_for_channel) {
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0], byte_for_channel * n,
buf, sdata->multiread_bit);
} else {
u8 *rx_array;
rx_array = kmalloc(byte_for_channel * num_data_channels,
GFP_KERNEL);
if (!rx_array) {
len = -ENOMEM;
goto st_sensors_free_memory;
}
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0],
byte_for_channel * num_data_channels,
rx_array, sdata->multiread_bit);
if (len < 0) {
kfree(rx_array);
goto st_sensors_free_memory;
}
for (i = 0; i < n * byte_for_channel; i++) {
if (i < n)
buf[i] = rx_array[i];
else
buf[i] = rx_array[n + i];
}
kfree(rx_array);
len = byte_for_channel * n;
}
break;
case 3:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], byte_for_channel * num_data_channels,
buf, sdata->multiread_bit);
break;
default:
len = -EINVAL;
goto st_sensors_free_memory;
}
if (len != byte_for_channel * n) {
len = -EIO;
goto st_sensors_free_memory;
}
st_sensors_free_memory:
kfree(addr);
st_sensors_get_buffer_element_error:
return len;
}
EXPORT_SYMBOL(st_sensors_get_buffer_element);
irqreturn_t st_sensors_trigger_handler(int irq, void *p)
{
int len;
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct st_sensor_data *sdata = iio_priv(indio_dev);
len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
if (len < 0)
goto st_sensors_get_buffer_element_error;
iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data,
pf->timestamp);
st_sensors_get_buffer_element_error:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
EXPORT_SYMBOL(st_sensors_trigger_handler);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,548 @@
/*
* STMicroelectronics sensors core library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
#define ST_SENSORS_WAI_ADDRESS 0x0f
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
}
static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data)
{
int err;
u8 new_data;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
if (err < 0)
goto st_sensors_write_data_with_mask_error;
new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
st_sensors_write_data_with_mask_error:
return err;
}
static int st_sensors_match_odr(struct st_sensors *sensor,
unsigned int odr, struct st_sensor_odr_avl *odr_out)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sensor->odr.odr_avl[i].hz == 0)
goto st_sensors_match_odr_error;
if (sensor->odr.odr_avl[i].hz == odr) {
odr_out->hz = sensor->odr.odr_avl[i].hz;
odr_out->value = sensor->odr.odr_avl[i].value;
ret = 0;
break;
}
}
st_sensors_match_odr_error:
return ret;
}
int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
{
int err;
struct st_sensor_odr_avl odr_out = {0, 0};
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
if (err < 0)
goto st_sensors_match_odr_error;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
if (sdata->enabled == true) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr,
sdata->sensor->odr.mask,
odr_out.value);
} else {
err = 0;
}
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr, sdata->sensor->odr.mask,
odr_out.value);
}
if (err >= 0)
sdata->odr = odr_out.hz;
st_sensors_match_odr_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_odr);
static int st_sensors_match_fs(struct st_sensors *sensor,
unsigned int fs, int *index_fs_avl)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sensor->fs.fs_avl[i].num == 0)
goto st_sensors_match_odr_error;
if (sensor->fs.fs_avl[i].num == fs) {
*index_fs_avl = i;
ret = 0;
break;
}
}
st_sensors_match_odr_error:
return ret;
}
static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
unsigned int fs)
{
int err, i = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_fs(sdata->sensor, fs, &i);
if (err < 0)
goto st_accel_set_fullscale_error;
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->fs.addr,
sdata->sensor->fs.mask,
sdata->sensor->fs.fs_avl[i].value);
if (err < 0)
goto st_accel_set_fullscale_error;
sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&sdata->sensor->fs.fs_avl[i];
return err;
st_accel_set_fullscale_error:
dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
return err;
}
int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
{
u8 tmp_value;
int err = -EINVAL;
bool found = false;
struct st_sensor_odr_avl odr_out = {0, 0};
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (enable) {
tmp_value = sdata->sensor->pw.value_on;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
err = st_sensors_match_odr(sdata->sensor,
sdata->odr, &odr_out);
if (err < 0)
goto set_enable_error;
tmp_value = odr_out.value;
found = true;
}
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask, tmp_value);
if (err < 0)
goto set_enable_error;
sdata->enabled = true;
if (found)
sdata->odr = odr_out.hz;
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask,
sdata->sensor->pw.value_off);
if (err < 0)
goto set_enable_error;
sdata->enabled = false;
}
set_enable_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_enable);
int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->enable_axis.addr,
sdata->sensor->enable_axis.mask, axis_enable);
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
void st_sensors_power_enable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
int err;
/* Regulators not mandatory, but if requested we should enable them. */
pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
if (!IS_ERR(pdata->vdd)) {
err = regulator_enable(pdata->vdd);
if (err != 0)
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd supply\n");
}
pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
if (!IS_ERR(pdata->vdd_io)) {
err = regulator_enable(pdata->vdd_io);
if (err != 0)
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd_IO supply\n");
}
}
EXPORT_SYMBOL(st_sensors_power_enable);
void st_sensors_power_disable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
if (!IS_ERR(pdata->vdd))
regulator_disable(pdata->vdd);
if (!IS_ERR(pdata->vdd_io))
regulator_disable(pdata->vdd_io);
}
EXPORT_SYMBOL(st_sensors_power_disable);
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
switch (pdata->drdy_int_pin) {
case 1:
if (sdata->sensor->drdy_irq.mask_int1 == 0) {
dev_err(&indio_dev->dev,
"DRDY on INT1 not available.\n");
return -EINVAL;
}
sdata->drdy_int_pin = 1;
break;
case 2:
if (sdata->sensor->drdy_irq.mask_int2 == 0) {
dev_err(&indio_dev->dev,
"DRDY on INT2 not available.\n");
return -EINVAL;
}
sdata->drdy_int_pin = 2;
break;
default:
dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
return -EINVAL;
}
return 0;
}
#ifdef CONFIG_OF
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
struct st_sensors_platform_data *defdata)
{
struct st_sensors_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 val;
if (!np)
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
pdata->drdy_int_pin = (u8) val;
else
pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 1;
return pdata;
}
#else
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
struct st_sensors_platform_data *defdata)
{
return NULL;
}
#endif
int st_sensors_init_sensor(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
struct st_sensors_platform_data *of_pdata;
int err = 0;
mutex_init(&sdata->tb.buf_lock);
/* If OF/DT pdata exists, it will take precedence of anything else */
of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
if (of_pdata)
pdata = of_pdata;
if (pdata) {
err = st_sensors_set_drdy_int_pin(indio_dev, pdata);
if (err < 0)
return err;
}
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
return err;
if (sdata->current_fullscale) {
err = st_sensors_set_fullscale(indio_dev,
sdata->current_fullscale->num);
if (err < 0)
return err;
} else
dev_info(&indio_dev->dev, "Full-scale not possible\n");
err = st_sensors_set_odr(indio_dev, sdata->odr);
if (err < 0)
return err;
/* set BDU */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
if (err < 0)
return err;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
return err;
}
EXPORT_SYMBOL(st_sensors_init_sensor);
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
{
int err;
u8 drdy_mask;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor->drdy_irq.addr)
return 0;
/* Enable/Disable the interrupt generator 1. */
if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.ig1.en_addr,
sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
if (err < 0)
goto st_accel_set_dataready_irq_error;
}
if (sdata->drdy_int_pin == 1)
drdy_mask = sdata->sensor->drdy_irq.mask_int1;
else
drdy_mask = sdata->sensor->drdy_irq.mask_int2;
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_dataready_irq);
int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
{
int err = -EINVAL, i;
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
(sdata->sensor->fs.fs_avl[i].gain != 0)) {
err = 0;
break;
}
}
if (err < 0)
goto st_sensors_match_scale_error;
err = st_sensors_set_fullscale(indio_dev,
sdata->sensor->fs.fs_avl[i].num);
st_sensors_match_scale_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *data)
{
int err;
u8 *outdata;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;
outdata = kmalloc(byte_for_channel, GFP_KERNEL);
if (!outdata)
return -ENOMEM;
err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
ch->address, byte_for_channel,
outdata, sdata->multiread_bit);
if (err < 0)
goto st_sensors_free_memory;
if (byte_for_channel == 2)
*data = (s16)get_unaligned_le16(outdata);
else if (byte_for_channel == 3)
*data = (s32)st_sensors_get_unaligned_le24(outdata);
st_sensors_free_memory:
kfree(outdata);
return err;
}
int st_sensors_read_info_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
err = -EBUSY;
goto out;
} else {
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto out;
msleep((sdata->sensor->bootime * 1000) / sdata->odr);
err = st_sensors_read_axis_data(indio_dev, ch, val);
if (err < 0)
goto out;
*val = *val >> ch->scan_type.shift;
err = st_sensors_set_enable(indio_dev, false);
}
out:
mutex_unlock(&indio_dev->mlock);
return err;
}
EXPORT_SYMBOL(st_sensors_read_info_raw);
int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list, const struct st_sensors *sensors)
{
u8 wai;
int i, n, err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
goto read_wai_error;
}
for (i = 0; i < num_sensors_list; i++) {
if (sensors[i].wai == wai)
break;
}
if (i == num_sensors_list)
goto device_not_supported;
for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
if (strcmp(indio_dev->name,
&sensors[i].sensors_supported[n][0]) == 0)
break;
}
if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
goto sensor_name_mismatch;
}
sdata->sensor = (struct st_sensors *)&sensors[i];
return i;
device_not_supported:
dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
sensor_name_mismatch:
err = -ENODEV;
read_wai_error:
return err;
}
EXPORT_SYMBOL(st_sensors_check_device_support);
ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, len = 0;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sdata->sensor->odr.odr_avl[i].hz == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
sdata->sensor->odr.odr_avl[i].hz);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';
return len;
}
EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, len = 0;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sdata->sensor->fs.fs_avl[i].num == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
sdata->sensor->fs.fs_avl[i].gain);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';
return len;
}
EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,111 @@
/*
* STMicroelectronics sensors i2c library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/of_device.h>
#include <linux/iio/common/st_sensors_i2c.h>
#define ST_SENSORS_I2C_MULTIREAD 0x80
static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_i2c_client(sdata->dev)->irq;
}
static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
int err;
err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
if (err < 0)
goto st_accel_i2c_read_byte_error;
*res_byte = err & 0xff;
st_accel_i2c_read_byte_error:
return err < 0 ? err : 0;
}
static int st_sensors_i2c_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
if (multiread_bit)
reg_addr |= ST_SENSORS_I2C_MULTIREAD;
return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
reg_addr, len, data);
}
static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
}
static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
.read_byte = st_sensors_i2c_read_byte,
.write_byte = st_sensors_i2c_write_byte,
.read_multiple_byte = st_sensors_i2c_read_multiple_byte,
};
void st_sensors_i2c_configure(struct iio_dev *indio_dev,
struct i2c_client *client, struct st_sensor_data *sdata)
{
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = client->name;
sdata->tf = &st_sensors_tf_i2c;
sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
}
EXPORT_SYMBOL(st_sensors_i2c_configure);
#ifdef CONFIG_OF
/**
* st_sensors_of_i2c_probe() - device tree probe for ST I2C sensors
* @client: the I2C client device for the sensor
* @match: the OF match table for the device, containing compatible strings
* but also a .data field with the corresponding internal kernel name
* used by this sensor.
*
* In effect this function matches a compatible string to an internal kernel
* name for a certain sensor device, so that the rest of the autodetection can
* rely on that name from this point on. I2C client devices will be renamed
* to match the internal kernel convention.
*/
void st_sensors_of_i2c_probe(struct i2c_client *client,
const struct of_device_id *match)
{
const struct of_device_id *of_id;
of_id = of_match_device(match, &client->dev);
if (!of_id)
return;
/* The name from the OF match takes precedence if present */
strncpy(client->name, of_id->data, sizeof(client->name));
client->name[sizeof(client->name) - 1] = '\0';
}
EXPORT_SYMBOL(st_sensors_of_i2c_probe);
#endif
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,121 @@
/*
* STMicroelectronics sensors spi library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/st_sensors_spi.h>
#define ST_SENSORS_SPI_MULTIREAD 0xc0
#define ST_SENSORS_SPI_READ 0x80
static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_spi_device(sdata->dev)->irq;
}
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
int err;
struct spi_transfer xfers[] = {
{
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 1,
},
{
.rx_buf = tb->rx_buf,
.bits_per_word = 8,
.len = len,
}
};
mutex_lock(&tb->buf_lock);
if ((multiread_bit) && (len > 1))
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
else
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers));
if (err)
goto acc_spi_read_error;
memcpy(data, tb->rx_buf, len*sizeof(u8));
mutex_unlock(&tb->buf_lock);
return len;
acc_spi_read_error:
mutex_unlock(&tb->buf_lock);
return err;
}
static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
}
static int st_sensors_spi_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
}
static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
int err;
struct spi_transfer xfers = {
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 2,
};
mutex_lock(&tb->buf_lock);
tb->tx_buf[0] = reg_addr;
tb->tx_buf[1] = data;
err = spi_sync_transfer(to_spi_device(dev), &xfers, 1);
mutex_unlock(&tb->buf_lock);
return err;
}
static const struct st_sensor_transfer_function st_sensors_tf_spi = {
.read_byte = st_sensors_spi_read_byte,
.write_byte = st_sensors_spi_write_byte,
.read_multiple_byte = st_sensors_spi_read_multiple_byte,
};
void st_sensors_spi_configure(struct iio_dev *indio_dev,
struct spi_device *spi, struct st_sensor_data *sdata)
{
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi->modalias;
sdata->tf = &st_sensors_tf_spi;
sdata->get_irq_data_ready = st_sensors_spi_get_irq;
}
EXPORT_SYMBOL(st_sensors_spi_configure);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,77 @@
/*
* STMicroelectronics sensors trigger library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/iio/common/st_sensors.h>
int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
const struct iio_trigger_ops *trigger_ops)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
if (sdata->trig == NULL) {
err = -ENOMEM;
dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
goto iio_trigger_alloc_error;
}
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_RISING,
sdata->trig->name,
sdata->trig);
if (err)
goto request_irq_error;
iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;
err = iio_trigger_register(sdata->trig);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
goto iio_trigger_register_error;
}
indio_dev->trig = iio_trigger_get(sdata->trig);
return 0;
iio_trigger_register_error:
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
request_irq_error:
iio_trigger_free(sdata->trig);
iio_trigger_alloc_error:
return err;
}
EXPORT_SYMBOL(st_sensors_allocate_trigger);
void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
iio_trigger_unregister(sdata->trig);
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
iio_trigger_free(sdata->trig);
}
EXPORT_SYMBOL(st_sensors_deallocate_trigger);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
MODULE_LICENSE("GPL v2");

184
drivers/iio/dac/Kconfig Normal file
View file

@ -0,0 +1,184 @@
#
# DAC drivers
#
# When adding new entries keep the list in alphabetical order
menu "Digital to analog converters"
config AD5064
tristate "Analog Devices AD5064 and similar multi-channel DAC driver"
depends on (SPI_MASTER && I2C!=m) || I2C
help
Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, AD5648, AD5666, AD5668,
AD5669R Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5064.
config AD5360
tristate "Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5360, AD5361,
AD5362, AD5363, AD5370, AD5371, AD5373 multi-channel
Digital to Analog Converters (DAC).
To compile this driver as module choose M here: the module will be called
ad5360.
config AD5380
tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver"
depends on (SPI_MASTER && I2C!=m) || I2C
select REGMAP_I2C if I2C
select REGMAP_SPI if SPI_MASTER
help
Say yes here to build support for Analog Devices AD5380, AD5381,
AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel
Digital to Analog Converters (DAC).
To compile this driver as module choose M here: the module will be called
ad5380.
config AD5421
tristate "Analog Devices AD5421 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5421 loop-powered
digital-to-analog convertors (DAC).
To compile this driver as module choose M here: the module will be called
ad5421.
config AD5446
tristate "Analog Devices AD5446 and similar single channel DACs driver"
depends on (SPI_MASTER && I2C!=m) || I2C
help
Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.
config AD5449
tristate "Analog Devices AD5449 and similar DACs driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5415, AD5426, AD5429,
AD5432, AD5439, AD5443, AD5449 Digital to Analog Converters.
To compile this driver as a module, choose M here: the
module will be called ad5449.
config AD5504
tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5504, AD5501,
High Voltage Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5504.
config AD5624R_SPI
tristate "Analog Devices AD5624/44/64R DAC spi driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5624R, AD5644R and
AD5664R converters (DAC). This driver uses the common SPI interface.
config AD5686
tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5686R, AD5685R,
AD5684R, AD5791 Voltage Output Digital to
Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5686.
config AD5755
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5755, AD5755-1,
AD5757, AD5735, AD5737 quad channel Digital to
Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5755.
config AD5764
tristate "Analog Devices AD5764/64R/44/44R DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744,
AD5744R Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5764.
config AD5791
tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5760, AD5780,
AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to
Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5791.
config AD7303
tristate "Analog Devices AD7303 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7303 Digital to Analog
Converters (DAC).
To compile this driver as module choose M here: the module will be called
ad7303.
config MAX517
tristate "Maxim MAX517/518/519 DAC driver"
depends on I2C
help
If you say yes here you get support for the Maxim chips MAX517,
MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
This driver can also be built as a module. If so, the module
will be called max517.
config MAX5821
tristate "Maxim MAX5821 DAC driver"
depends on I2C
depends on OF
help
Say yes here to build support for Maxim MAX5821
10 bits DAC.
config MCP4725
tristate "MCP4725 DAC driver"
depends on I2C
---help---
Say Y here if you want to build a driver for the Microchip
MCP 4725 12-bit digital-to-analog converter (DAC) with I2C
interface.
To compile this driver as a module, choose M here: the module
will be called mcp4725.
config MCP4922
tristate "MCP4902, MCP4912, MCP4922 DAC driver"
depends on SPI
help
Say yes here to build the driver for the Microchip MCP4902
MCP4912, and MCP4922 DAC devices.
To compile this driver as a module, choose M here: the module
will be called mcp4922.
endmenu

22
drivers/iio/dac/Makefile Normal file
View file

@ -0,0 +1,22 @@
#
# Makefile for industrial I/O DAC drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD5360) += ad5360.o
obj-$(CONFIG_AD5380) += ad5380.o
obj-$(CONFIG_AD5421) += ad5421.o
obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5449) += ad5449.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o

684
drivers/iio/dac/ad5064.c Normal file
View file

@ -0,0 +1,684 @@
/*
* AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R,
* AD5648, AD5666, AD5668, AD5669R Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define AD5064_MAX_DAC_CHANNELS 8
#define AD5064_MAX_VREFS 4
#define AD5064_ADDR(x) ((x) << 20)
#define AD5064_CMD(x) ((x) << 24)
#define AD5064_ADDR_ALL_DAC 0xF
#define AD5064_CMD_WRITE_INPUT_N 0x0
#define AD5064_CMD_UPDATE_DAC_N 0x1
#define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
#define AD5064_CMD_WRITE_INPUT_N_UPDATE_N 0x3
#define AD5064_CMD_POWERDOWN_DAC 0x4
#define AD5064_CMD_CLEAR 0x5
#define AD5064_CMD_LDAC_MASK 0x6
#define AD5064_CMD_RESET 0x7
#define AD5064_CMD_CONFIG 0x8
#define AD5064_CONFIG_DAISY_CHAIN_ENABLE BIT(1)
#define AD5064_CONFIG_INT_VREF_ENABLE BIT(0)
#define AD5064_LDAC_PWRDN_NONE 0x0
#define AD5064_LDAC_PWRDN_1K 0x1
#define AD5064_LDAC_PWRDN_100K 0x2
#define AD5064_LDAC_PWRDN_3STATE 0x3
/**
* struct ad5064_chip_info - chip specific information
* @shared_vref: whether the vref supply is shared between channels
* @internal_vref: internal reference voltage. 0 if the chip has no internal
* vref.
* @channel: channel specification
* @num_channels: number of channels
*/
struct ad5064_chip_info {
bool shared_vref;
unsigned long internal_vref;
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
struct ad5064_state;
typedef int (*ad5064_write_func)(struct ad5064_state *st, unsigned int cmd,
unsigned int addr, unsigned int val);
/**
* struct ad5064_state - driver instance specific data
* @dev: the device for this driver instance
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulators
* @pwr_down: whether channel is powered down
* @pwr_down_mode: channel's current power down mode
* @dac_cache: current DAC raw value (chip does not support readback)
* @use_internal_vref: set to true if the internal reference voltage should be
* used.
* @write: register write callback
* @data: i2c/spi transfer buffers
*/
struct ad5064_state {
struct device *dev;
const struct ad5064_chip_info *chip_info;
struct regulator_bulk_data vref_reg[AD5064_MAX_VREFS];
bool pwr_down[AD5064_MAX_DAC_CHANNELS];
u8 pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
unsigned int dac_cache[AD5064_MAX_DAC_CHANNELS];
bool use_internal_vref;
ad5064_write_func write;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
u8 i2c[3];
__be32 spi;
} data ____cacheline_aligned;
};
enum ad5064_type {
ID_AD5024,
ID_AD5025,
ID_AD5044,
ID_AD5045,
ID_AD5064,
ID_AD5064_1,
ID_AD5065,
ID_AD5628_1,
ID_AD5628_2,
ID_AD5648_1,
ID_AD5648_2,
ID_AD5666_1,
ID_AD5666_2,
ID_AD5668_1,
ID_AD5668_2,
};
static int ad5064_write(struct ad5064_state *st, unsigned int cmd,
unsigned int addr, unsigned int val, unsigned int shift)
{
val <<= shift;
return st->write(st, cmd, addr, val);
}
static int ad5064_sync_powerdown_mode(struct ad5064_state *st,
const struct iio_chan_spec *chan)
{
unsigned int val;
int ret;
val = (0x1 << chan->address);
if (st->pwr_down[chan->channel])
val |= st->pwr_down_mode[chan->channel] << 8;
ret = ad5064_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0);
return ret;
}
static const char * const ad5064_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"three_state",
};
static int ad5064_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5064_state *st = iio_priv(indio_dev);
return st->pwr_down_mode[chan->channel] - 1;
}
static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5064_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
st->pwr_down_mode[chan->channel] = mode + 1;
ret = ad5064_sync_powerdown_mode(st, chan);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static const struct iio_enum ad5064_powerdown_mode_enum = {
.items = ad5064_powerdown_modes,
.num_items = ARRAY_SIZE(ad5064_powerdown_modes),
.get = ad5064_get_powerdown_mode,
.set = ad5064_set_powerdown_mode,
};
static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5064_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
}
static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
struct ad5064_state *st = iio_priv(indio_dev);
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
st->pwr_down[chan->channel] = pwr_down;
ret = ad5064_sync_powerdown_mode(st, chan);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static int ad5064_get_vref(struct ad5064_state *st,
struct iio_chan_spec const *chan)
{
unsigned int i;
if (st->use_internal_vref)
return st->chip_info->internal_vref;
i = st->chip_info->shared_vref ? 0 : chan->channel;
return regulator_get_voltage(st->vref_reg[i].consumer);
}
static int ad5064_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5064_state *st = iio_priv(indio_dev);
int scale_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
*val = st->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = ad5064_get_vref(st, chan);
if (scale_uv < 0)
return scale_uv;
*val = scale_uv / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static int ad5064_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct ad5064_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
chan->address, val, chan->scan_type.shift);
if (ret == 0)
st->dac_cache[chan->channel] = val;
mutex_unlock(&indio_dev->mlock);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info ad5064_info = {
.read_raw = ad5064_read_raw,
.write_raw = ad5064_write_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
{
.name = "powerdown",
.read = ad5064_read_dac_powerdown,
.write = ad5064_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum),
{ },
};
#define AD5064_CHANNEL(chan, addr, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.address = addr, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = 20 - bits, \
}, \
.ext_info = ad5064_ext_info, \
}
#define DECLARE_AD5064_CHANNELS(name, bits) \
const struct iio_chan_spec name[] = { \
AD5064_CHANNEL(0, 0, bits), \
AD5064_CHANNEL(1, 1, bits), \
AD5064_CHANNEL(2, 2, bits), \
AD5064_CHANNEL(3, 3, bits), \
AD5064_CHANNEL(4, 4, bits), \
AD5064_CHANNEL(5, 5, bits), \
AD5064_CHANNEL(6, 6, bits), \
AD5064_CHANNEL(7, 7, bits), \
}
#define DECLARE_AD5065_CHANNELS(name, bits) \
const struct iio_chan_spec name[] = { \
AD5064_CHANNEL(0, 0, bits), \
AD5064_CHANNEL(1, 3, bits), \
}
static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
static DECLARE_AD5065_CHANNELS(ad5025_channels, 12);
static DECLARE_AD5065_CHANNELS(ad5045_channels, 14);
static DECLARE_AD5065_CHANNELS(ad5065_channels, 16);
static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
[ID_AD5024] = {
.shared_vref = false,
.channels = ad5024_channels,
.num_channels = 4,
},
[ID_AD5025] = {
.shared_vref = false,
.channels = ad5025_channels,
.num_channels = 2,
},
[ID_AD5044] = {
.shared_vref = false,
.channels = ad5044_channels,
.num_channels = 4,
},
[ID_AD5045] = {
.shared_vref = false,
.channels = ad5045_channels,
.num_channels = 2,
},
[ID_AD5064] = {
.shared_vref = false,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5064_1] = {
.shared_vref = true,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5065] = {
.shared_vref = false,
.channels = ad5065_channels,
.num_channels = 2,
},
[ID_AD5628_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5024_channels,
.num_channels = 8,
},
[ID_AD5628_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5024_channels,
.num_channels = 8,
},
[ID_AD5648_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5044_channels,
.num_channels = 8,
},
[ID_AD5648_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5044_channels,
.num_channels = 8,
},
[ID_AD5666_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5666_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5668_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5064_channels,
.num_channels = 8,
},
[ID_AD5668_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5064_channels,
.num_channels = 8,
},
};
static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
{
return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
}
static const char * const ad5064_vref_names[] = {
"vrefA",
"vrefB",
"vrefC",
"vrefD",
};
static const char * const ad5064_vref_name(struct ad5064_state *st,
unsigned int vref)
{
return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref];
}
static int ad5064_probe(struct device *dev, enum ad5064_type type,
const char *name, ad5064_write_func write)
{
struct iio_dev *indio_dev;
struct ad5064_state *st;
unsigned int midscale;
unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
st->chip_info = &ad5064_chip_info_tbl[type];
st->dev = dev;
st->write = write;
for (i = 0; i < ad5064_num_vref(st); ++i)
st->vref_reg[i].supply = ad5064_vref_name(st, i);
ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st),
st->vref_reg);
if (ret) {
if (!st->chip_info->internal_vref)
return ret;
st->use_internal_vref = true;
ret = ad5064_write(st, AD5064_CMD_CONFIG, 0,
AD5064_CONFIG_INT_VREF_ENABLE, 0);
if (ret) {
dev_err(dev, "Failed to enable internal vref: %d\n",
ret);
return ret;
}
} else {
ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
if (ret)
return ret;
}
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &ad5064_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
midscale = (1 << indio_dev->channels[0].scan_type.realbits) / 2;
for (i = 0; i < st->chip_info->num_channels; ++i) {
st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
st->dac_cache[i] = midscale;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!st->use_internal_vref)
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
return ret;
}
static int ad5064_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5064_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!st->use_internal_vref)
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
return 0;
}
#if IS_ENABLED(CONFIG_SPI_MASTER)
static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
unsigned int addr, unsigned int val)
{
struct spi_device *spi = to_spi_device(st->dev);
st->data.spi = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val);
return spi_write(spi, &st->data.spi, sizeof(st->data.spi));
}
static int ad5064_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
return ad5064_probe(&spi->dev, id->driver_data, id->name,
ad5064_spi_write);
}
static int ad5064_spi_remove(struct spi_device *spi)
{
return ad5064_remove(&spi->dev);
}
static const struct spi_device_id ad5064_spi_ids[] = {
{"ad5024", ID_AD5024},
{"ad5025", ID_AD5025},
{"ad5044", ID_AD5044},
{"ad5045", ID_AD5045},
{"ad5064", ID_AD5064},
{"ad5064-1", ID_AD5064_1},
{"ad5065", ID_AD5065},
{"ad5628-1", ID_AD5628_1},
{"ad5628-2", ID_AD5628_2},
{"ad5648-1", ID_AD5648_1},
{"ad5648-2", ID_AD5648_2},
{"ad5666-1", ID_AD5666_1},
{"ad5666-2", ID_AD5666_2},
{"ad5668-1", ID_AD5668_1},
{"ad5668-2", ID_AD5668_2},
{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
{}
};
MODULE_DEVICE_TABLE(spi, ad5064_spi_ids);
static struct spi_driver ad5064_spi_driver = {
.driver = {
.name = "ad5064",
.owner = THIS_MODULE,
},
.probe = ad5064_spi_probe,
.remove = ad5064_spi_remove,
.id_table = ad5064_spi_ids,
};
static int __init ad5064_spi_register_driver(void)
{
return spi_register_driver(&ad5064_spi_driver);
}
static void ad5064_spi_unregister_driver(void)
{
spi_unregister_driver(&ad5064_spi_driver);
}
#else
static inline int ad5064_spi_register_driver(void) { return 0; }
static inline void ad5064_spi_unregister_driver(void) { }
#endif
#if IS_ENABLED(CONFIG_I2C)
static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
unsigned int addr, unsigned int val)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
st->data.i2c[0] = (cmd << 4) | addr;
put_unaligned_be16(val, &st->data.i2c[1]);
return i2c_master_send(i2c, st->data.i2c, 3);
}
static int ad5064_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
return ad5064_probe(&i2c->dev, id->driver_data, id->name,
ad5064_i2c_write);
}
static int ad5064_i2c_remove(struct i2c_client *i2c)
{
return ad5064_remove(&i2c->dev);
}
static const struct i2c_device_id ad5064_i2c_ids[] = {
{"ad5629-1", ID_AD5628_1},
{"ad5629-2", ID_AD5628_2},
{"ad5629-3", ID_AD5628_2}, /* similar enough to ad5629-2 */
{"ad5669-1", ID_AD5668_1},
{"ad5669-2", ID_AD5668_2},
{"ad5669-3", ID_AD5668_2}, /* similar enough to ad5669-2 */
{}
};
MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
static struct i2c_driver ad5064_i2c_driver = {
.driver = {
.name = "ad5064",
.owner = THIS_MODULE,
},
.probe = ad5064_i2c_probe,
.remove = ad5064_i2c_remove,
.id_table = ad5064_i2c_ids,
};
static int __init ad5064_i2c_register_driver(void)
{
return i2c_add_driver(&ad5064_i2c_driver);
}
static void __exit ad5064_i2c_unregister_driver(void)
{
i2c_del_driver(&ad5064_i2c_driver);
}
#else
static inline int ad5064_i2c_register_driver(void) { return 0; }
static inline void ad5064_i2c_unregister_driver(void) { }
#endif
static int __init ad5064_init(void)
{
int ret;
ret = ad5064_spi_register_driver();
if (ret)
return ret;
ret = ad5064_i2c_register_driver();
if (ret) {
ad5064_spi_unregister_driver();
return ret;
}
return 0;
}
module_init(ad5064_init);
static void __exit ad5064_exit(void)
{
ad5064_i2c_unregister_driver();
ad5064_spi_unregister_driver();
}
module_exit(ad5064_exit);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5024 and similar multi-channel DACs");
MODULE_LICENSE("GPL v2");

562
drivers/iio/dac/ad5360.c Normal file
View file

@ -0,0 +1,562 @@
/*
* Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373
* multi-channel Digital to Analog Converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define AD5360_CMD(x) ((x) << 22)
#define AD5360_ADDR(x) ((x) << 16)
#define AD5360_READBACK_TYPE(x) ((x) << 13)
#define AD5360_READBACK_ADDR(x) ((x) << 7)
#define AD5360_CHAN_ADDR(chan) ((chan) + 0x8)
#define AD5360_CMD_WRITE_DATA 0x3
#define AD5360_CMD_WRITE_OFFSET 0x2
#define AD5360_CMD_WRITE_GAIN 0x1
#define AD5360_CMD_SPECIAL_FUNCTION 0x0
/* Special function register addresses */
#define AD5360_REG_SF_NOP 0x0
#define AD5360_REG_SF_CTRL 0x1
#define AD5360_REG_SF_OFS(x) (0x2 + (x))
#define AD5360_REG_SF_READBACK 0x5
#define AD5360_SF_CTRL_PWR_DOWN BIT(0)
#define AD5360_READBACK_X1A 0x0
#define AD5360_READBACK_X1B 0x1
#define AD5360_READBACK_OFFSET 0x2
#define AD5360_READBACK_GAIN 0x3
#define AD5360_READBACK_SF 0x4
/**
* struct ad5360_chip_info - chip specific information
* @channel_template: channel specification template
* @num_channels: number of channels
* @channels_per_group: number of channels per group
* @num_vrefs: number of vref supplies for the chip
*/
struct ad5360_chip_info {
struct iio_chan_spec channel_template;
unsigned int num_channels;
unsigned int channels_per_group;
unsigned int num_vrefs;
};
/**
* struct ad5360_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulators
* @ctrl: control register cache
* @data: spi transfer buffers
*/
struct ad5360_state {
struct spi_device *spi;
const struct ad5360_chip_info *chip_info;
struct regulator_bulk_data vref_reg[3];
unsigned int ctrl;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
} data[2] ____cacheline_aligned;
};
enum ad5360_type {
ID_AD5360,
ID_AD5361,
ID_AD5362,
ID_AD5363,
ID_AD5370,
ID_AD5371,
ID_AD5372,
ID_AD5373,
};
#define AD5360_CHANNEL(bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = 16 - (bits), \
}, \
}
static const struct ad5360_chip_info ad5360_chip_info_tbl[] = {
[ID_AD5360] = {
.channel_template = AD5360_CHANNEL(16),
.num_channels = 16,
.channels_per_group = 8,
.num_vrefs = 2,
},
[ID_AD5361] = {
.channel_template = AD5360_CHANNEL(14),
.num_channels = 16,
.channels_per_group = 8,
.num_vrefs = 2,
},
[ID_AD5362] = {
.channel_template = AD5360_CHANNEL(16),
.num_channels = 8,
.channels_per_group = 4,
.num_vrefs = 2,
},
[ID_AD5363] = {
.channel_template = AD5360_CHANNEL(14),
.num_channels = 8,
.channels_per_group = 4,
.num_vrefs = 2,
},
[ID_AD5370] = {
.channel_template = AD5360_CHANNEL(16),
.num_channels = 40,
.channels_per_group = 8,
.num_vrefs = 2,
},
[ID_AD5371] = {
.channel_template = AD5360_CHANNEL(14),
.num_channels = 40,
.channels_per_group = 8,
.num_vrefs = 3,
},
[ID_AD5372] = {
.channel_template = AD5360_CHANNEL(16),
.num_channels = 32,
.channels_per_group = 8,
.num_vrefs = 2,
},
[ID_AD5373] = {
.channel_template = AD5360_CHANNEL(14),
.num_channels = 32,
.channels_per_group = 8,
.num_vrefs = 2,
},
};
static unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st,
unsigned int channel)
{
unsigned int i;
/* The first groups have their own vref, while the remaining groups
* share the last vref */
i = channel / st->chip_info->channels_per_group;
if (i >= st->chip_info->num_vrefs)
i = st->chip_info->num_vrefs - 1;
return i;
}
static int ad5360_get_channel_vref(struct ad5360_state *st,
unsigned int channel)
{
unsigned int i = ad5360_get_channel_vref_index(st, channel);
return regulator_get_voltage(st->vref_reg[i].consumer);
}
static int ad5360_write_unlocked(struct iio_dev *indio_dev,
unsigned int cmd, unsigned int addr, unsigned int val,
unsigned int shift)
{
struct ad5360_state *st = iio_priv(indio_dev);
val <<= shift;
val |= AD5360_CMD(cmd) | AD5360_ADDR(addr);
st->data[0].d32 = cpu_to_be32(val);
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
unsigned int addr, unsigned int val, unsigned int shift)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
unsigned int addr)
{
struct ad5360_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.rx_buf = &st->data[1].d8[1],
.len = 3,
},
};
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
AD5360_ADDR(AD5360_REG_SF_READBACK) |
AD5360_READBACK_TYPE(type) |
AD5360_READBACK_ADDR(addr));
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
return ret;
}
static ssize_t ad5360_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5360_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
}
static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
unsigned int clr)
{
struct ad5360_state *st = iio_priv(indio_dev);
unsigned int ret;
mutex_lock(&indio_dev->mlock);
st->ctrl |= set;
st->ctrl &= ~clr;
ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
AD5360_REG_SF_CTRL, st->ctrl, 0);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static ssize_t ad5360_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
if (pwr_down)
ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0);
else
ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN);
return ret ? ret : len;
}
static IIO_DEVICE_ATTR(out_voltage_powerdown,
S_IRUGO | S_IWUSR,
ad5360_read_dac_powerdown,
ad5360_write_dac_powerdown, 0);
static struct attribute *ad5360_attributes[] = {
&iio_dev_attr_out_voltage_powerdown.dev_attr.attr,
NULL,
};
static const struct attribute_group ad5360_attribute_group = {
.attrs = ad5360_attributes,
};
static int ad5360_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5360_state *st = iio_priv(indio_dev);
int max_val = (1 << chan->scan_type.realbits);
unsigned int ofs_index;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA,
chan->address, val, chan->scan_type.shift);
case IIO_CHAN_INFO_CALIBBIAS:
if (val >= max_val || val < 0)
return -EINVAL;
return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET,
chan->address, val, chan->scan_type.shift);
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= max_val || val < 0)
return -EINVAL;
return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN,
chan->address, val, chan->scan_type.shift);
case IIO_CHAN_INFO_OFFSET:
if (val <= -max_val || val > 0)
return -EINVAL;
val = -val;
/* offset is supposed to have the same scale as raw, but it
* is always 14bits wide, so on a chip where the raw value has
* more bits, we need to shift offset. */
val >>= (chan->scan_type.realbits - 14);
/* There is one DAC offset register per vref. Changing one
* channels offset will also change the offset for all other
* channels which share the same vref supply. */
ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
AD5360_REG_SF_OFS(ofs_index), val, 0);
default:
break;
}
return -EINVAL;
}
static int ad5360_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5360_state *st = iio_priv(indio_dev);
unsigned int ofs_index;
int scale_uv;
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
chan->address);
if (ret < 0)
return ret;
*val = ret >> chan->scan_type.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = ad5360_get_channel_vref(st, chan->channel);
if (scale_uv < 0)
return scale_uv;
/* vout = 4 * vref * dac_code */
*val = scale_uv * 4 / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_CALIBBIAS:
ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET,
chan->address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN,
chan->address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
ret = ad5360_read(indio_dev, AD5360_READBACK_SF,
AD5360_REG_SF_OFS(ofs_index));
if (ret < 0)
return ret;
ret <<= (chan->scan_type.realbits - 14);
*val = -ret;
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info ad5360_info = {
.read_raw = ad5360_read_raw,
.write_raw = ad5360_write_raw,
.attrs = &ad5360_attribute_group,
.driver_module = THIS_MODULE,
};
static const char * const ad5360_vref_name[] = {
"vref0", "vref1", "vref2"
};
static int ad5360_alloc_channels(struct iio_dev *indio_dev)
{
struct ad5360_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels;
unsigned int i;
channels = kcalloc(st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;
for (i = 0; i < st->chip_info->num_channels; ++i) {
channels[i] = st->chip_info->channel_template;
channels[i].channel = i;
channels[i].address = AD5360_CHAN_ADDR(i);
}
indio_dev->channels = channels;
return 0;
}
static int ad5360_probe(struct spi_device *spi)
{
enum ad5360_type type = spi_get_device_id(spi)->driver_data;
struct iio_dev *indio_dev;
struct ad5360_state *st;
unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->chip_info = &ad5360_chip_info_tbl[type];
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5360_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = st->chip_info->num_channels;
ret = ad5360_alloc_channels(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
return ret;
}
for (i = 0; i < st->chip_info->num_vrefs; ++i)
st->vref_reg[i].supply = ad5360_vref_name[i];
ret = devm_regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
goto error_free_channels;
}
ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
goto error_free_channels;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
goto error_disable_reg;
}
return 0;
error_disable_reg:
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
error_free_channels:
kfree(indio_dev->channels);
return ret;
}
static int ad5360_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5360_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
kfree(indio_dev->channels);
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
return 0;
}
static const struct spi_device_id ad5360_ids[] = {
{ "ad5360", ID_AD5360 },
{ "ad5361", ID_AD5361 },
{ "ad5362", ID_AD5362 },
{ "ad5363", ID_AD5363 },
{ "ad5370", ID_AD5370 },
{ "ad5371", ID_AD5371 },
{ "ad5372", ID_AD5372 },
{ "ad5373", ID_AD5373 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5360_ids);
static struct spi_driver ad5360_driver = {
.driver = {
.name = "ad5360",
.owner = THIS_MODULE,
},
.probe = ad5360_probe,
.remove = ad5360_remove,
.id_table = ad5360_ids,
};
module_spi_driver(ad5360_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC");
MODULE_LICENSE("GPL v2");

654
drivers/iio/dac/ad5380.c Normal file
View file

@ -0,0 +1,654 @@
/*
* Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392
* multi-channel Digital to Analog Converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define AD5380_REG_DATA(x) (((x) << 2) | 3)
#define AD5380_REG_OFFSET(x) (((x) << 2) | 2)
#define AD5380_REG_GAIN(x) (((x) << 2) | 1)
#define AD5380_REG_SF_PWR_DOWN (8 << 2)
#define AD5380_REG_SF_PWR_UP (9 << 2)
#define AD5380_REG_SF_CTRL (12 << 2)
#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET 13
#define AD5380_CTRL_INT_VREF_2V5 BIT(12)
#define AD5380_CTRL_INT_VREF_EN BIT(10)
/**
* struct ad5380_chip_info - chip specific information
* @channel_template: channel specification template
* @num_channels: number of channels
* @int_vref: internal vref in uV
*/
struct ad5380_chip_info {
struct iio_chan_spec channel_template;
unsigned int num_channels;
unsigned int int_vref;
};
/**
* struct ad5380_state - driver instance specific data
* @regmap: regmap instance used by the device
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulator
* @vref: actual reference voltage used in uA
* @pwr_down: whether the chip is currently in power down mode
*/
struct ad5380_state {
struct regmap *regmap;
const struct ad5380_chip_info *chip_info;
struct regulator *vref_reg;
int vref;
bool pwr_down;
};
enum ad5380_type {
ID_AD5380_3,
ID_AD5380_5,
ID_AD5381_3,
ID_AD5381_5,
ID_AD5382_3,
ID_AD5382_5,
ID_AD5383_3,
ID_AD5383_5,
ID_AD5390_3,
ID_AD5390_5,
ID_AD5391_3,
ID_AD5391_5,
ID_AD5392_3,
ID_AD5392_5,
};
static ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5380_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
struct ad5380_state *st = iio_priv(indio_dev);
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
if (pwr_down)
ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
else
ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0);
st->pwr_down = pwr_down;
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static const char * const ad5380_powerdown_modes[] = {
"100kohm_to_gnd",
"three_state",
};
static int ad5380_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5380_state *st = iio_priv(indio_dev);
unsigned int mode;
int ret;
ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode);
if (ret)
return ret;
mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1;
return mode;
}
static int ad5380_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5380_state *st = iio_priv(indio_dev);
int ret;
ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL,
1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET,
mode << AD5380_CTRL_PWR_DOWN_MODE_OFFSET);
return ret;
}
static const struct iio_enum ad5380_powerdown_mode_enum = {
.items = ad5380_powerdown_modes,
.num_items = ARRAY_SIZE(ad5380_powerdown_modes),
.get = ad5380_get_powerdown_mode,
.set = ad5380_set_powerdown_mode,
};
static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
long info)
{
switch (info) {
case 0:
return AD5380_REG_DATA(chan->address);
case IIO_CHAN_INFO_CALIBBIAS:
return AD5380_REG_OFFSET(chan->address);
case IIO_CHAN_INFO_CALIBSCALE:
return AD5380_REG_GAIN(chan->address);
default:
break;
}
return 0;
}
static int ad5380_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
const unsigned int max_val = (1 << chan->scan_type.realbits);
struct ad5380_state *st = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= max_val || val < 0)
return -EINVAL;
return regmap_write(st->regmap,
ad5380_info_to_reg(chan, info),
val << chan->scan_type.shift);
case IIO_CHAN_INFO_CALIBBIAS:
val += (1 << chan->scan_type.realbits) / 2;
if (val >= max_val || val < 0)
return -EINVAL;
return regmap_write(st->regmap,
AD5380_REG_OFFSET(chan->address),
val << chan->scan_type.shift);
default:
break;
}
return -EINVAL;
}
static int ad5380_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct ad5380_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
val);
if (ret)
return ret;
*val >>= chan->scan_type.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address),
val);
if (ret)
return ret;
*val >>= chan->scan_type.shift;
val -= (1 << chan->scan_type.realbits) / 2;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 2 * st->vref;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static const struct iio_info ad5380_info = {
.read_raw = ad5380_read_raw,
.write_raw = ad5380_write_raw,
.driver_module = THIS_MODULE,
};
static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
{
.name = "powerdown",
.read = ad5380_read_dac_powerdown,
.write = ad5380_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5380_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum),
{ },
};
#define AD5380_CHANNEL(_bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 14 - (_bits), \
}, \
.ext_info = ad5380_ext_info, \
}
static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
[ID_AD5380_3] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 40,
.int_vref = 1250,
},
[ID_AD5380_5] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 40,
.int_vref = 2500,
},
[ID_AD5381_3] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 16,
.int_vref = 1250,
},
[ID_AD5381_5] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 16,
.int_vref = 2500,
},
[ID_AD5382_3] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 32,
.int_vref = 1250,
},
[ID_AD5382_5] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 32,
.int_vref = 2500,
},
[ID_AD5383_3] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 32,
.int_vref = 1250,
},
[ID_AD5383_5] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 32,
.int_vref = 2500,
},
[ID_AD5390_3] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 16,
.int_vref = 1250,
},
[ID_AD5390_5] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 16,
.int_vref = 2500,
},
[ID_AD5391_3] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 16,
.int_vref = 1250,
},
[ID_AD5391_5] = {
.channel_template = AD5380_CHANNEL(12),
.num_channels = 16,
.int_vref = 2500,
},
[ID_AD5392_3] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 8,
.int_vref = 1250,
},
[ID_AD5392_5] = {
.channel_template = AD5380_CHANNEL(14),
.num_channels = 8,
.int_vref = 2500,
},
};
static int ad5380_alloc_channels(struct iio_dev *indio_dev)
{
struct ad5380_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels;
unsigned int i;
channels = kcalloc(st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;
for (i = 0; i < st->chip_info->num_channels; ++i) {
channels[i] = st->chip_info->channel_template;
channels[i].channel = i;
channels[i].address = i;
}
indio_dev->channels = channels;
return 0;
}
static int ad5380_probe(struct device *dev, struct regmap *regmap,
enum ad5380_type type, const char *name)
{
struct iio_dev *indio_dev;
struct ad5380_state *st;
unsigned int ctrl = 0;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
st->chip_info = &ad5380_chip_info_tbl[type];
st->regmap = regmap;
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &ad5380_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = st->chip_info->num_channels;
ret = ad5380_alloc_channels(indio_dev);
if (ret) {
dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
return ret;
}
if (st->chip_info->int_vref == 2500)
ctrl |= AD5380_CTRL_INT_VREF_2V5;
st->vref_reg = devm_regulator_get(dev, "vref");
if (!IS_ERR(st->vref_reg)) {
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(dev, "Failed to enable vref regulators: %d\n",
ret);
goto error_free_reg;
}
ret = regulator_get_voltage(st->vref_reg);
if (ret < 0)
goto error_disable_reg;
st->vref = ret / 1000;
} else {
st->vref = st->chip_info->int_vref;
ctrl |= AD5380_CTRL_INT_VREF_EN;
}
ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
if (ret) {
dev_err(dev, "Failed to write to device: %d\n", ret);
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "Failed to register iio device: %d\n", ret);
goto error_disable_reg;
}
return 0;
error_disable_reg:
if (!IS_ERR(st->vref_reg))
regulator_disable(st->vref_reg);
error_free_reg:
kfree(indio_dev->channels);
return ret;
}
static int ad5380_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5380_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
kfree(indio_dev->channels);
if (!IS_ERR(st->vref_reg)) {
regulator_disable(st->vref_reg);
}
return 0;
}
static bool ad5380_reg_false(struct device *dev, unsigned int reg)
{
return false;
}
static const struct regmap_config ad5380_regmap_config = {
.reg_bits = 10,
.val_bits = 14,
.max_register = AD5380_REG_DATA(40),
.cache_type = REGCACHE_RBTREE,
.volatile_reg = ad5380_reg_false,
.readable_reg = ad5380_reg_false,
};
#if IS_ENABLED(CONFIG_SPI_MASTER)
static int ad5380_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &ad5380_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
}
static int ad5380_spi_remove(struct spi_device *spi)
{
return ad5380_remove(&spi->dev);
}
static const struct spi_device_id ad5380_spi_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
{ "ad5381-3", ID_AD5381_3 },
{ "ad5381-5", ID_AD5381_5 },
{ "ad5382-3", ID_AD5382_3 },
{ "ad5382-5", ID_AD5382_5 },
{ "ad5383-3", ID_AD5383_3 },
{ "ad5383-5", ID_AD5383_5 },
{ "ad5384-3", ID_AD5380_3 },
{ "ad5384-5", ID_AD5380_5 },
{ "ad5390-3", ID_AD5390_3 },
{ "ad5390-5", ID_AD5390_5 },
{ "ad5391-3", ID_AD5391_3 },
{ "ad5391-5", ID_AD5391_5 },
{ "ad5392-3", ID_AD5392_3 },
{ "ad5392-5", ID_AD5392_5 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
static struct spi_driver ad5380_spi_driver = {
.driver = {
.name = "ad5380",
.owner = THIS_MODULE,
},
.probe = ad5380_spi_probe,
.remove = ad5380_spi_remove,
.id_table = ad5380_spi_ids,
};
static inline int ad5380_spi_register_driver(void)
{
return spi_register_driver(&ad5380_spi_driver);
}
static inline void ad5380_spi_unregister_driver(void)
{
spi_unregister_driver(&ad5380_spi_driver);
}
#else
static inline int ad5380_spi_register_driver(void)
{
return 0;
}
static inline void ad5380_spi_unregister_driver(void)
{
}
#endif
#if IS_ENABLED(CONFIG_I2C)
static int ad5380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(i2c, &ad5380_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
}
static int ad5380_i2c_remove(struct i2c_client *i2c)
{
return ad5380_remove(&i2c->dev);
}
static const struct i2c_device_id ad5380_i2c_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
{ "ad5381-3", ID_AD5381_3 },
{ "ad5381-5", ID_AD5381_5 },
{ "ad5382-3", ID_AD5382_3 },
{ "ad5382-5", ID_AD5382_5 },
{ "ad5383-3", ID_AD5383_3 },
{ "ad5383-5", ID_AD5383_5 },
{ "ad5384-3", ID_AD5380_3 },
{ "ad5384-5", ID_AD5380_5 },
{ "ad5390-3", ID_AD5390_3 },
{ "ad5390-5", ID_AD5390_5 },
{ "ad5391-3", ID_AD5391_3 },
{ "ad5391-5", ID_AD5391_5 },
{ "ad5392-3", ID_AD5392_3 },
{ "ad5392-5", ID_AD5392_5 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
static struct i2c_driver ad5380_i2c_driver = {
.driver = {
.name = "ad5380",
.owner = THIS_MODULE,
},
.probe = ad5380_i2c_probe,
.remove = ad5380_i2c_remove,
.id_table = ad5380_i2c_ids,
};
static inline int ad5380_i2c_register_driver(void)
{
return i2c_add_driver(&ad5380_i2c_driver);
}
static inline void ad5380_i2c_unregister_driver(void)
{
i2c_del_driver(&ad5380_i2c_driver);
}
#else
static inline int ad5380_i2c_register_driver(void)
{
return 0;
}
static inline void ad5380_i2c_unregister_driver(void)
{
}
#endif
static int __init ad5380_spi_init(void)
{
int ret;
ret = ad5380_spi_register_driver();
if (ret)
return ret;
ret = ad5380_i2c_register_driver();
if (ret) {
ad5380_spi_unregister_driver();
return ret;
}
return 0;
}
module_init(ad5380_spi_init);
static void __exit ad5380_spi_exit(void)
{
ad5380_i2c_unregister_driver();
ad5380_spi_unregister_driver();
}
module_exit(ad5380_spi_exit);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC");
MODULE_LICENSE("GPL v2");

536
drivers/iio/dac/ad5421.c Normal file
View file

@ -0,0 +1,536 @@
/*
* AD5421 Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/dac/ad5421.h>
#define AD5421_REG_DAC_DATA 0x1
#define AD5421_REG_CTRL 0x2
#define AD5421_REG_OFFSET 0x3
#define AD5421_REG_GAIN 0x4
/* load dac and fault shared the same register number. Writing to it will cause
* a dac load command, reading from it will return the fault status register */
#define AD5421_REG_LOAD_DAC 0x5
#define AD5421_REG_FAULT 0x5
#define AD5421_REG_FORCE_ALARM_CURRENT 0x6
#define AD5421_REG_RESET 0x7
#define AD5421_REG_START_CONVERSION 0x8
#define AD5421_REG_NOOP 0x9
#define AD5421_CTRL_WATCHDOG_DISABLE BIT(12)
#define AD5421_CTRL_AUTO_FAULT_READBACK BIT(11)
#define AD5421_CTRL_MIN_CURRENT BIT(9)
#define AD5421_CTRL_ADC_SOURCE_TEMP BIT(8)
#define AD5421_CTRL_ADC_ENABLE BIT(7)
#define AD5421_CTRL_PWR_DOWN_INT_VREF BIT(6)
#define AD5421_FAULT_SPI BIT(15)
#define AD5421_FAULT_PEC BIT(14)
#define AD5421_FAULT_OVER_CURRENT BIT(13)
#define AD5421_FAULT_UNDER_CURRENT BIT(12)
#define AD5421_FAULT_TEMP_OVER_140 BIT(11)
#define AD5421_FAULT_TEMP_OVER_100 BIT(10)
#define AD5421_FAULT_UNDER_VOLTAGE_6V BIT(9)
#define AD5421_FAULT_UNDER_VOLTAGE_12V BIT(8)
/* These bits will cause the fault pin to go high */
#define AD5421_FAULT_TRIGGER_IRQ \
(AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)
/**
* struct ad5421_state - driver instance specific data
* @spi: spi_device
* @ctrl: control register cache
* @current_range: current range which the device is configured for
* @data: spi transfer buffers
* @fault_mask: software masking of events
*/
struct ad5421_state {
struct spi_device *spi;
unsigned int ctrl;
enum ad5421_current_range current_range;
unsigned int fault_mask;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
} data[2] ____cacheline_aligned;
};
static const struct iio_event_spec ad5421_current_event[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_event_spec ad5421_temp_event[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_chan_spec ad5421_channels[] = {
{
.type = IIO_CURRENT,
.indexed = 1,
.output = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBSCALE) |
BIT(IIO_CHAN_INFO_CALIBBIAS),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
},
.event_spec = ad5421_current_event,
.num_event_specs = ARRAY_SIZE(ad5421_current_event),
},
{
.type = IIO_TEMP,
.channel = -1,
.event_spec = ad5421_temp_event,
.num_event_specs = ARRAY_SIZE(ad5421_temp_event),
},
};
static int ad5421_write_unlocked(struct iio_dev *indio_dev,
unsigned int reg, unsigned int val)
{
struct ad5421_state *st = iio_priv(indio_dev);
st->data[0].d32 = cpu_to_be32((reg << 16) | val);
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5421_write_unlocked(indio_dev, reg, val);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
{
struct ad5421_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.rx_buf = &st->data[1].d8[1],
.len = 3,
},
};
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
unsigned int clr)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int ret;
mutex_lock(&indio_dev->mlock);
st->ctrl &= ~clr;
st->ctrl |= set;
ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static irqreturn_t ad5421_fault_handler(int irq, void *data)
{
struct iio_dev *indio_dev = data;
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int fault;
unsigned int old_fault = 0;
unsigned int events;
fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
if (!fault)
return IRQ_NONE;
/* If we had a fault, this might mean that the DAC has lost its state
* and has been reset. Make sure that the control register actually
* contains what we expect it to contain. Otherwise the watchdog might
* be enabled and we get watchdog timeout faults, which will render the
* DAC unusable. */
ad5421_update_ctrl(indio_dev, 0, 0);
/* The fault pin stays high as long as a fault condition is present and
* it is not possible to mask fault conditions. For certain fault
* conditions for example like over-temperature it takes some time
* until the fault condition disappears. If we would exit the interrupt
* handler immediately after handling the event it would be entered
* again instantly. Thus we fall back to polling in case we detect that
* a interrupt condition is still present.
*/
do {
/* 0xffff is a invalid value for the register and will only be
* read if there has been a communication error */
if (fault == 0xffff)
fault = 0;
/* we are only interested in new events */
events = (old_fault ^ fault) & fault;
events &= st->fault_mask;
if (events & AD5421_FAULT_OVER_CURRENT) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns());
}
if (events & AD5421_FAULT_UNDER_CURRENT) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns());
}
if (events & AD5421_FAULT_TEMP_OVER_140) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_RISING),
iio_get_time_ns());
}
old_fault = fault;
fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
/* still active? go to sleep for some time */
if (fault & AD5421_FAULT_TRIGGER_IRQ)
msleep(1000);
} while (fault & AD5421_FAULT_TRIGGER_IRQ);
return IRQ_HANDLED;
}
static void ad5421_get_current_min_max(struct ad5421_state *st,
unsigned int *min, unsigned int *max)
{
/* The current range is configured using external pins, which are
* usually hard-wired and not run-time switchable. */
switch (st->current_range) {
case AD5421_CURRENT_RANGE_4mA_20mA:
*min = 4000;
*max = 20000;
break;
case AD5421_CURRENT_RANGE_3mA8_21mA:
*min = 3800;
*max = 21000;
break;
case AD5421_CURRENT_RANGE_3mA2_24mA:
*min = 3200;
*max = 24000;
break;
default:
*min = 0;
*max = 1;
break;
}
}
static inline unsigned int ad5421_get_offset(struct ad5421_state *st)
{
unsigned int min, max;
ad5421_get_current_min_max(st, &min, &max);
return (min * (1 << 16)) / (max - min);
}
static int ad5421_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long m)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int min, max;
int ret;
if (chan->type != IIO_CURRENT)
return -EINVAL;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ad5421_get_current_min_max(st, &min, &max);
*val = max - min;
*val2 = (1 << 16) * 1000;
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_OFFSET:
*val = ad5421_get_offset(st);
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
if (ret < 0)
return ret;
*val = ret - 32768;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad5421_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
const unsigned int max_val = 1 << 16;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
case IIO_CHAN_INFO_CALIBBIAS:
val += 32768;
if (val >= max_val || val < 0)
return -EINVAL;
return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= max_val || val < 0)
return -EINVAL;
return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
default:
break;
}
return -EINVAL;
}
static int ad5421_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int mask;
switch (chan->type) {
case IIO_CURRENT:
if (dir == IIO_EV_DIR_RISING)
mask = AD5421_FAULT_OVER_CURRENT;
else
mask = AD5421_FAULT_UNDER_CURRENT;
break;
case IIO_TEMP:
mask = AD5421_FAULT_TEMP_OVER_140;
break;
default:
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
if (state)
st->fault_mask |= mask;
else
st->fault_mask &= ~mask;
mutex_unlock(&indio_dev->mlock);
return 0;
}
static int ad5421_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int mask;
switch (chan->type) {
case IIO_CURRENT:
if (dir == IIO_EV_DIR_RISING)
mask = AD5421_FAULT_OVER_CURRENT;
else
mask = AD5421_FAULT_UNDER_CURRENT;
break;
case IIO_TEMP:
mask = AD5421_FAULT_TEMP_OVER_140;
break;
default:
return -EINVAL;
}
return (bool)(st->fault_mask & mask);
}
static int ad5421_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info, int *val,
int *val2)
{
int ret;
switch (chan->type) {
case IIO_CURRENT:
ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
if (ret < 0)
return ret;
*val = ret;
break;
case IIO_TEMP:
*val = 140000;
break;
default:
return -EINVAL;
}
return IIO_VAL_INT;
}
static const struct iio_info ad5421_info = {
.read_raw = ad5421_read_raw,
.write_raw = ad5421_write_raw,
.read_event_config = ad5421_read_event_config,
.write_event_config = ad5421_write_event_config,
.read_event_value = ad5421_read_event_value,
.driver_module = THIS_MODULE,
};
static int ad5421_probe(struct spi_device *spi)
{
struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5421_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = "ad5421";
indio_dev->info = &ad5421_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad5421_channels;
indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
AD5421_CTRL_AUTO_FAULT_READBACK;
if (pdata) {
st->current_range = pdata->current_range;
if (pdata->external_vref)
st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
} else {
st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
}
/* write initial ctrl register value */
ad5421_update_ctrl(indio_dev, 0, 0);
if (spi->irq) {
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL,
ad5421_fault_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"ad5421 fault",
indio_dev);
if (ret)
return ret;
}
return devm_iio_device_register(&spi->dev, indio_dev);
}
static struct spi_driver ad5421_driver = {
.driver = {
.name = "ad5421",
.owner = THIS_MODULE,
},
.probe = ad5421_probe,
};
module_spi_driver(ad5421_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:ad5421");

623
drivers/iio/dac/ad5446.c Normal file
View file

@ -0,0 +1,623 @@
/*
* AD5446 SPI DAC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define MODE_PWRDWN_1k 0x1
#define MODE_PWRDWN_100k 0x2
#define MODE_PWRDWN_TRISTATE 0x3
/**
* struct ad5446_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
*/
struct ad5446_state {
struct device *dev;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
unsigned pwr_down;
};
/**
* struct ad5446_chip_info - chip specific information
* @channel: channel spec for the DAC
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @write: chip specific helper function to write to the register
*/
struct ad5446_chip_info {
struct iio_chan_spec channel;
u16 int_vref_mv;
int (*write)(struct ad5446_state *st, unsigned val);
};
static const char * const ad5446_powerdown_modes[] = {
"1kohm_to_gnd", "100kohm_to_gnd", "three_state"
};
static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5446_state *st = iio_priv(indio_dev);
st->pwr_down_mode = mode + 1;
return 0;
}
static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5446_state *st = iio_priv(indio_dev);
return st->pwr_down_mode - 1;
}
static const struct iio_enum ad5446_powerdown_mode_enum = {
.items = ad5446_powerdown_modes,
.num_items = ARRAY_SIZE(ad5446_powerdown_modes),
.get = ad5446_get_powerdown_mode,
.set = ad5446_set_powerdown_mode,
};
static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct ad5446_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct ad5446_state *st = iio_priv(indio_dev);
unsigned int shift;
unsigned int val;
bool powerdown;
int ret;
ret = strtobool(buf, &powerdown);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
st->pwr_down = powerdown;
if (st->pwr_down) {
shift = chan->scan_type.realbits + chan->scan_type.shift;
val = st->pwr_down_mode << shift;
} else {
val = st->cached_val;
}
ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
{
.name = "powerdown",
.read = ad5446_read_dac_powerdown,
.write = ad5446_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum),
{ },
};
#define _AD5446_CHANNEL(bits, storage, _shift, ext) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = (storage), \
.shift = (_shift), \
}, \
.ext_info = (ext), \
}
#define AD5446_CHANNEL(bits, storage, shift) \
_AD5446_CHANNEL(bits, storage, shift, NULL)
#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
_AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown)
static int ad5446_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5446_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
*val = st->cached_val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ad5446_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5446_state *st = iio_priv(indio_dev);
int ret = 0;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
mutex_lock(&indio_dev->mlock);
st->cached_val = val;
if (!st->pwr_down)
ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info ad5446_info = {
.read_raw = ad5446_read_raw,
.write_raw = ad5446_write_raw,
.driver_module = THIS_MODULE,
};
static int ad5446_probe(struct device *dev, const char *name,
const struct ad5446_chip_info *chip_info)
{
struct ad5446_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
int ret, voltage_uv = 0;
reg = devm_regulator_get(dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
}
st = iio_priv(indio_dev);
st->chip_info = chip_info;
dev_set_drvdata(dev, indio_dev);
st->reg = reg;
st->dev = dev;
/* Establish that the iio_dev is a child of the device */
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &ad5446_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
st->pwr_down_mode = MODE_PWRDWN_1k;
if (st->chip_info->int_vref_mv)
st->vref_mv = st->chip_info->int_vref_mv;
else if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
dev_warn(dev, "reference voltage unspecified\n");
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
return ret;
}
static int ad5446_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
}
#if IS_ENABLED(CONFIG_SPI_MASTER)
static int ad5446_write(struct ad5446_state *st, unsigned val)
{
struct spi_device *spi = to_spi_device(st->dev);
__be16 data = cpu_to_be16(val);
return spi_write(spi, &data, sizeof(data));
}
static int ad5660_write(struct ad5446_state *st, unsigned val)
{
struct spi_device *spi = to_spi_device(st->dev);
uint8_t data[3];
data[0] = (val >> 16) & 0xFF;
data[1] = (val >> 8) & 0xFF;
data[2] = val & 0xFF;
return spi_write(spi, data, sizeof(data));
}
/**
* ad5446_supported_spi_device_ids:
* The AD5620/40/60 parts are available in different fixed internal reference
* voltage options. The actual part numbers may look differently
* (and a bit cryptic), however this style is used to make clear which
* parts are supported here.
*/
enum ad5446_supported_spi_device_ids {
ID_AD5300,
ID_AD5310,
ID_AD5320,
ID_AD5444,
ID_AD5446,
ID_AD5450,
ID_AD5451,
ID_AD5541A,
ID_AD5512A,
ID_AD5553,
ID_AD5601,
ID_AD5611,
ID_AD5621,
ID_AD5641,
ID_AD5620_2500,
ID_AD5620_1250,
ID_AD5640_2500,
ID_AD5640_1250,
ID_AD5660_2500,
ID_AD5660_1250,
ID_AD5662,
};
static const struct ad5446_chip_info ad5446_spi_chip_info[] = {
[ID_AD5300] = {
.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
.write = ad5446_write,
},
[ID_AD5310] = {
.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
.write = ad5446_write,
},
[ID_AD5320] = {
.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
.write = ad5446_write,
},
[ID_AD5444] = {
.channel = AD5446_CHANNEL(12, 16, 2),
.write = ad5446_write,
},
[ID_AD5446] = {
.channel = AD5446_CHANNEL(14, 16, 0),
.write = ad5446_write,
},
[ID_AD5450] = {
.channel = AD5446_CHANNEL(8, 16, 6),
.write = ad5446_write,
},
[ID_AD5451] = {
.channel = AD5446_CHANNEL(10, 16, 4),
.write = ad5446_write,
},
[ID_AD5541A] = {
.channel = AD5446_CHANNEL(16, 16, 0),
.write = ad5446_write,
},
[ID_AD5512A] = {
.channel = AD5446_CHANNEL(12, 16, 4),
.write = ad5446_write,
},
[ID_AD5553] = {
.channel = AD5446_CHANNEL(14, 16, 0),
.write = ad5446_write,
},
[ID_AD5601] = {
.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
.write = ad5446_write,
},
[ID_AD5611] = {
.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
.write = ad5446_write,
},
[ID_AD5621] = {
.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.write = ad5446_write,
},
[ID_AD5641] = {
.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.write = ad5446_write,
},
[ID_AD5620_2500] = {
.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 2500,
.write = ad5446_write,
},
[ID_AD5620_1250] = {
.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 1250,
.write = ad5446_write,
},
[ID_AD5640_2500] = {
.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 2500,
.write = ad5446_write,
},
[ID_AD5640_1250] = {
.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 1250,
.write = ad5446_write,
},
[ID_AD5660_2500] = {
.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 2500,
.write = ad5660_write,
},
[ID_AD5660_1250] = {
.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 1250,
.write = ad5660_write,
},
[ID_AD5662] = {
.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.write = ad5660_write,
},
};
static const struct spi_device_id ad5446_spi_ids[] = {
{"ad5300", ID_AD5300},
{"ad5310", ID_AD5310},
{"ad5320", ID_AD5320},
{"ad5444", ID_AD5444},
{"ad5446", ID_AD5446},
{"ad5450", ID_AD5450},
{"ad5451", ID_AD5451},
{"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */
{"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */
{"ad5512a", ID_AD5512A},
{"ad5541a", ID_AD5541A},
{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
{"ad5553", ID_AD5553},
{"ad5601", ID_AD5601},
{"ad5611", ID_AD5611},
{"ad5621", ID_AD5621},
{"ad5641", ID_AD5641},
{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
{"ad5640-2500", ID_AD5640_2500},
{"ad5640-1250", ID_AD5640_1250},
{"ad5660-2500", ID_AD5660_2500},
{"ad5660-1250", ID_AD5660_1250},
{"ad5662", ID_AD5662},
{}
};
MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
static int ad5446_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
return ad5446_probe(&spi->dev, id->name,
&ad5446_spi_chip_info[id->driver_data]);
}
static int ad5446_spi_remove(struct spi_device *spi)
{
return ad5446_remove(&spi->dev);
}
static struct spi_driver ad5446_spi_driver = {
.driver = {
.name = "ad5446",
.owner = THIS_MODULE,
},
.probe = ad5446_spi_probe,
.remove = ad5446_spi_remove,
.id_table = ad5446_spi_ids,
};
static int __init ad5446_spi_register_driver(void)
{
return spi_register_driver(&ad5446_spi_driver);
}
static void ad5446_spi_unregister_driver(void)
{
spi_unregister_driver(&ad5446_spi_driver);
}
#else
static inline int ad5446_spi_register_driver(void) { return 0; }
static inline void ad5446_spi_unregister_driver(void) { }
#endif
#if IS_ENABLED(CONFIG_I2C)
static int ad5622_write(struct ad5446_state *st, unsigned val)
{
struct i2c_client *client = to_i2c_client(st->dev);
__be16 data = cpu_to_be16(val);
return i2c_master_send(client, (char *)&data, sizeof(data));
}
/**
* ad5446_supported_i2c_device_ids:
* The AD5620/40/60 parts are available in different fixed internal reference
* voltage options. The actual part numbers may look differently
* (and a bit cryptic), however this style is used to make clear which
* parts are supported here.
*/
enum ad5446_supported_i2c_device_ids {
ID_AD5602,
ID_AD5612,
ID_AD5622,
};
static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
[ID_AD5602] = {
.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4),
.write = ad5622_write,
},
[ID_AD5612] = {
.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2),
.write = ad5622_write,
},
[ID_AD5622] = {
.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0),
.write = ad5622_write,
},
};
static int ad5446_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
return ad5446_probe(&i2c->dev, id->name,
&ad5446_i2c_chip_info[id->driver_data]);
}
static int ad5446_i2c_remove(struct i2c_client *i2c)
{
return ad5446_remove(&i2c->dev);
}
static const struct i2c_device_id ad5446_i2c_ids[] = {
{"ad5301", ID_AD5602},
{"ad5311", ID_AD5612},
{"ad5321", ID_AD5622},
{"ad5602", ID_AD5602},
{"ad5612", ID_AD5612},
{"ad5622", ID_AD5622},
{}
};
MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
static struct i2c_driver ad5446_i2c_driver = {
.driver = {
.name = "ad5446",
.owner = THIS_MODULE,
},
.probe = ad5446_i2c_probe,
.remove = ad5446_i2c_remove,
.id_table = ad5446_i2c_ids,
};
static int __init ad5446_i2c_register_driver(void)
{
return i2c_add_driver(&ad5446_i2c_driver);
}
static void __exit ad5446_i2c_unregister_driver(void)
{
i2c_del_driver(&ad5446_i2c_driver);
}
#else
static inline int ad5446_i2c_register_driver(void) { return 0; }
static inline void ad5446_i2c_unregister_driver(void) { }
#endif
static int __init ad5446_init(void)
{
int ret;
ret = ad5446_spi_register_driver();
if (ret)
return ret;
ret = ad5446_i2c_register_driver();
if (ret) {
ad5446_spi_unregister_driver();
return ret;
}
return 0;
}
module_init(ad5446_init);
static void __exit ad5446_exit(void)
{
ad5446_i2c_unregister_driver();
ad5446_spi_unregister_driver();
}
module_exit(ad5446_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
MODULE_LICENSE("GPL v2");

369
drivers/iio/dac/ad5449.c Normal file
View file

@ -0,0 +1,369 @@
/*
* AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog
* Converter driver.
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/ad5449.h>
#define AD5449_MAX_CHANNELS 2
#define AD5449_MAX_VREFS 2
#define AD5449_CMD_NOOP 0x0
#define AD5449_CMD_LOAD_AND_UPDATE(x) (0x1 + (x) * 3)
#define AD5449_CMD_READ(x) (0x2 + (x) * 3)
#define AD5449_CMD_LOAD(x) (0x3 + (x) * 3)
#define AD5449_CMD_CTRL 13
#define AD5449_CTRL_SDO_OFFSET 10
#define AD5449_CTRL_DAISY_CHAIN BIT(9)
#define AD5449_CTRL_HCLR_TO_MIDSCALE BIT(8)
#define AD5449_CTRL_SAMPLE_RISING BIT(7)
/**
* struct ad5449_chip_info - chip specific information
* @channels: Channel specification
* @num_channels: Number of channels
* @has_ctrl: Chip has a control register
*/
struct ad5449_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
bool has_ctrl;
};
/**
* struct ad5449 - driver instance specific data
* @spi: the SPI device for this driver instance
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulators
* @has_sdo: whether the SDO line is connected
* @dac_cache: Cache for the DAC values
* @data: spi transfer buffers
*/
struct ad5449 {
struct spi_device *spi;
const struct ad5449_chip_info *chip_info;
struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS];
bool has_sdo;
uint16_t dac_cache[AD5449_MAX_CHANNELS];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 data[2] ____cacheline_aligned;
};
enum ad5449_type {
ID_AD5426,
ID_AD5429,
ID_AD5432,
ID_AD5439,
ID_AD5443,
ID_AD5449,
};
static int ad5449_write(struct iio_dev *indio_dev, unsigned int addr,
unsigned int val)
{
struct ad5449 *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
st->data[0] = cpu_to_be16((addr << 12) | val);
ret = spi_write(st->spi, st->data, 2);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr,
unsigned int *val)
{
struct ad5449 *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0],
.len = 2,
.cs_change = 1,
}, {
.tx_buf = &st->data[1],
.rx_buf = &st->data[1],
.len = 2,
},
};
mutex_lock(&indio_dev->mlock);
st->data[0] = cpu_to_be16(addr << 12);
st->data[1] = cpu_to_be16(AD5449_CMD_NOOP);
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
goto out_unlock;
*val = be16_to_cpu(st->data[1]);
out_unlock:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5449_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct ad5449 *st = iio_priv(indio_dev);
struct regulator_bulk_data *reg;
int scale_uv;
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
if (st->has_sdo) {
ret = ad5449_read(indio_dev,
AD5449_CMD_READ(chan->address), val);
if (ret)
return ret;
*val &= 0xfff;
} else {
*val = st->dac_cache[chan->address];
}
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
reg = &st->vref_reg[chan->channel];
scale_uv = regulator_get_voltage(reg->consumer);
if (scale_uv < 0)
return scale_uv;
*val = scale_uv / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static int ad5449_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct ad5449 *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val >= (1 << chan->scan_type.realbits))
return -EINVAL;
ret = ad5449_write(indio_dev,
AD5449_CMD_LOAD_AND_UPDATE(chan->address),
val << chan->scan_type.shift);
if (ret == 0)
st->dac_cache[chan->address] = val;
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info ad5449_info = {
.read_raw = ad5449_read_raw,
.write_raw = ad5449_write_raw,
.driver_module = THIS_MODULE,
};
#define AD5449_CHANNEL(chan, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.address = (chan), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = 12 - (bits), \
}, \
}
#define DECLARE_AD5449_CHANNELS(name, bits) \
const struct iio_chan_spec name[] = { \
AD5449_CHANNEL(0, bits), \
AD5449_CHANNEL(1, bits), \
}
static DECLARE_AD5449_CHANNELS(ad5429_channels, 8);
static DECLARE_AD5449_CHANNELS(ad5439_channels, 10);
static DECLARE_AD5449_CHANNELS(ad5449_channels, 12);
static const struct ad5449_chip_info ad5449_chip_info[] = {
[ID_AD5426] = {
.channels = ad5429_channels,
.num_channels = 1,
.has_ctrl = false,
},
[ID_AD5429] = {
.channels = ad5429_channels,
.num_channels = 2,
.has_ctrl = true,
},
[ID_AD5432] = {
.channels = ad5439_channels,
.num_channels = 1,
.has_ctrl = false,
},
[ID_AD5439] = {
.channels = ad5439_channels,
.num_channels = 2,
.has_ctrl = true,
},
[ID_AD5443] = {
.channels = ad5449_channels,
.num_channels = 1,
.has_ctrl = false,
},
[ID_AD5449] = {
.channels = ad5449_channels,
.num_channels = 2,
.has_ctrl = true,
},
};
static const char *ad5449_vref_name(struct ad5449 *st, int n)
{
if (st->chip_info->num_channels == 1)
return "VREF";
if (n == 0)
return "VREFA";
else
return "VREFB";
}
static int ad5449_spi_probe(struct spi_device *spi)
{
struct ad5449_platform_data *pdata = spi->dev.platform_data;
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct ad5449 *st;
unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->chip_info = &ad5449_chip_info[id->driver_data];
st->spi = spi;
for (i = 0; i < st->chip_info->num_channels; ++i)
st->vref_reg[i].supply = ad5449_vref_name(st, i);
ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
st->vref_reg);
if (ret)
return ret;
ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg);
if (ret)
return ret;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = id->name;
indio_dev->info = &ad5449_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
if (st->chip_info->has_ctrl) {
unsigned int ctrl = 0x00;
if (pdata) {
if (pdata->hardware_clear_to_midscale)
ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE;
ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET;
st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED;
} else {
st->has_sdo = true;
}
ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl);
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
return ret;
}
static int ad5449_spi_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5449 *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
return 0;
}
static const struct spi_device_id ad5449_spi_ids[] = {
{ "ad5415", ID_AD5449 },
{ "ad5426", ID_AD5426 },
{ "ad5429", ID_AD5429 },
{ "ad5432", ID_AD5432 },
{ "ad5439", ID_AD5439 },
{ "ad5443", ID_AD5443 },
{ "ad5449", ID_AD5449 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5449_spi_ids);
static struct spi_driver ad5449_spi_driver = {
.driver = {
.name = "ad5449",
.owner = THIS_MODULE,
},
.probe = ad5449_spi_probe,
.remove = ad5449_spi_remove,
.id_table = ad5449_spi_ids,
};
module_spi_driver(ad5449_spi_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5449 and similar DACs");
MODULE_LICENSE("GPL v2");

377
drivers/iio/dac/ad5504.c Normal file
View file

@ -0,0 +1,377 @@
/*
* AD5504, AD5501 High Voltage Digital to Analog Converter
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/dac/ad5504.h>
#define AD5504_RES_MASK GENMASK(11, 0)
#define AD5504_CMD_READ BIT(15)
#define AD5504_CMD_WRITE 0
#define AD5504_ADDR(addr) ((addr) << 12)
/* Registers */
#define AD5504_ADDR_NOOP 0
#define AD5504_ADDR_DAC(x) ((x) + 1)
#define AD5504_ADDR_ALL_DAC 5
#define AD5504_ADDR_CTRL 7
/* Control Register */
#define AD5504_DAC_PWR(ch) ((ch) << 2)
#define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6)
#define AD5504_DAC_PWRDN_20K 0
#define AD5504_DAC_PWRDN_3STATE 1
/**
* struct ad5446_state - driver instance specific data
* @spi: spi_device
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @pwr_down_mask power down mask
* @pwr_down_mode current power down mode
* @data: transfer buffer
*/
struct ad5504_state {
struct spi_device *spi;
struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;
__be16 data[2] ____cacheline_aligned;
};
/**
* ad5504_supported_device_ids:
*/
enum ad5504_supported_device_ids {
ID_AD5504,
ID_AD5501,
};
static int ad5504_spi_write(struct ad5504_state *st, u8 addr, u16 val)
{
st->data[0] = cpu_to_be16(AD5504_CMD_WRITE | AD5504_ADDR(addr) |
(val & AD5504_RES_MASK));
return spi_write(st->spi, &st->data[0], 2);
}
static int ad5504_spi_read(struct ad5504_state *st, u8 addr)
{
int ret;
struct spi_transfer t = {
.tx_buf = &st->data[0],
.rx_buf = &st->data[1],
.len = 2,
};
st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret < 0)
return ret;
return be16_to_cpu(st->data[1]) & AD5504_RES_MASK;
}
static int ad5504_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5504_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5504_spi_read(st, chan->address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ad5504_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5504_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
return ad5504_spi_write(st, chan->address, val);
default:
return -EINVAL;
}
}
static const char * const ad5504_powerdown_modes[] = {
"20kohm_to_gnd",
"three_state",
};
static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5504_state *st = iio_priv(indio_dev);
return st->pwr_down_mode;
}
static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5504_state *st = iio_priv(indio_dev);
st->pwr_down_mode = mode;
return 0;
}
static const struct iio_enum ad5504_powerdown_mode_enum = {
.items = ad5504_powerdown_modes,
.num_items = ARRAY_SIZE(ad5504_powerdown_modes),
.get = ad5504_get_powerdown_mode,
.set = ad5504_set_powerdown_mode,
};
static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5504_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
!(st->pwr_down_mask & (1 << chan->channel)));
}
static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
bool pwr_down;
int ret;
struct ad5504_state *st = iio_priv(indio_dev);
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
if (pwr_down)
st->pwr_down_mask |= (1 << chan->channel);
else
st->pwr_down_mask &= ~(1 << chan->channel);
ret = ad5504_spi_write(st, AD5504_ADDR_CTRL,
AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
AD5504_DAC_PWR(st->pwr_down_mask));
/* writes to the CTRL register must be followed by a NOOP */
ad5504_spi_write(st, AD5504_ADDR_NOOP, 0);
return ret ? ret : len;
}
static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
static struct attribute *ad5504_ev_attributes[] = {
&iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
&iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
NULL,
};
static struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes,
.name = "events",
};
static irqreturn_t ad5504_event_handler(int irq, void *private)
{
iio_push_event(private,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns());
return IRQ_HANDLED;
}
static const struct iio_info ad5504_info = {
.write_raw = ad5504_write_raw,
.read_raw = ad5504_read_raw,
.event_attrs = &ad5504_ev_attribute_group,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
{
.name = "powerdown",
.read = ad5504_read_dac_powerdown,
.write = ad5504_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5504_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum),
{ },
};
#define AD5504_CHANNEL(_chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = AD5504_ADDR_DAC(_chan), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
.ext_info = ad5504_ext_info, \
}
static const struct iio_chan_spec ad5504_channels[] = {
AD5504_CHANNEL(0),
AD5504_CHANNEL(1),
AD5504_CHANNEL(2),
AD5504_CHANNEL(3),
};
static int ad5504_probe(struct spi_device *spi)
{
struct ad5504_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad5504_state *st;
struct regulator *reg;
int ret, voltage_uv = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else if (pdata)
st->vref_mv = pdata->vref_mv;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
st->reg = reg;
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(st->spi)->name;
indio_dev->info = &ad5504_info;
if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
indio_dev->num_channels = 1;
else
indio_dev->num_channels = 4;
indio_dev->channels = ad5504_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
if (spi->irq) {
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL,
&ad5504_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi_get_device_id(st->spi)->name,
indio_dev);
if (ret)
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
return ret;
}
static int ad5504_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5504_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad5504_id[] = {
{"ad5504", ID_AD5504},
{"ad5501", ID_AD5501},
{}
};
MODULE_DEVICE_TABLE(spi, ad5504_id);
static struct spi_driver ad5504_driver = {
.driver = {
.name = "ad5504",
.owner = THIS_MODULE,
},
.probe = ad5504_probe,
.remove = ad5504_remove,
.id_table = ad5504_id,
};
module_spi_driver(ad5504_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
MODULE_LICENSE("GPL v2");

79
drivers/iio/dac/ad5624r.h Normal file
View file

@ -0,0 +1,79 @@
/*
* AD5624R SPI DAC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef SPI_AD5624R_H_
#define SPI_AD5624R_H_
#define AD5624R_DAC_CHANNELS 4
#define AD5624R_ADDR_DAC0 0x0
#define AD5624R_ADDR_DAC1 0x1
#define AD5624R_ADDR_DAC2 0x2
#define AD5624R_ADDR_DAC3 0x3
#define AD5624R_ADDR_ALL_DAC 0x7
#define AD5624R_CMD_WRITE_INPUT_N 0x0
#define AD5624R_CMD_UPDATE_DAC_N 0x1
#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3
#define AD5624R_CMD_POWERDOWN_DAC 0x4
#define AD5624R_CMD_RESET 0x5
#define AD5624R_CMD_LDAC_SETUP 0x6
#define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7
#define AD5624R_LDAC_PWRDN_NONE 0x0
#define AD5624R_LDAC_PWRDN_1K 0x1
#define AD5624R_LDAC_PWRDN_100K 0x2
#define AD5624R_LDAC_PWRDN_3STATE 0x3
/**
* struct ad5624r_chip_info - chip specific information
* @channels: channel spec for the DAC
* @int_vref_mv: AD5620/40/60: the internal reference voltage
*/
struct ad5624r_chip_info {
const struct iio_chan_spec *channels;
u16 int_vref_mv;
};
/**
* struct ad5446_state - driver instance specific data
* @indio_dev: the industrial I/O device
* @us: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @pwr_down_mask power down mask
* @pwr_down_mode current power down mode
*/
struct ad5624r_state {
struct spi_device *us;
const struct ad5624r_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;
};
/**
* ad5624r_supported_device_ids:
* The AD5624/44/64 parts are available in different
* fixed internal reference voltage options.
*/
enum ad5624r_supported_device_ids {
ID_AD5624R3,
ID_AD5644R3,
ID_AD5664R3,
ID_AD5624R5,
ID_AD5644R5,
ID_AD5664R5,
};
#endif /* SPI_AD5624R_H_ */

View file

@ -0,0 +1,319 @@
/*
* AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "ad5624r.h"
static int ad5624r_spi_write(struct spi_device *spi,
u8 cmd, u8 addr, u16 val, u8 len)
{
u32 data;
u8 msg[3];
/*
* The input shift register is 24 bits wide. The first two bits are
* don't care bits. The next three are the command bits, C2 to C0,
* followed by the 3-bit DAC address, A2 to A0, and then the
* 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
* 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
* for the AD5664R, AD5644R, and AD5624R, respectively.
*/
data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
msg[0] = data >> 16;
msg[1] = data >> 8;
msg[2] = data;
return spi_write(spi, msg, 3);
}
static int ad5624r_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5624r_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ad5624r_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5624r_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
return ad5624r_spi_write(st->us,
AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
chan->address, val,
chan->scan_type.shift);
default:
return -EINVAL;
}
}
static const char * const ad5624r_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"three_state"
};
static int ad5624r_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5624r_state *st = iio_priv(indio_dev);
return st->pwr_down_mode;
}
static int ad5624r_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5624r_state *st = iio_priv(indio_dev);
st->pwr_down_mode = mode;
return 0;
}
static const struct iio_enum ad5624r_powerdown_mode_enum = {
.items = ad5624r_powerdown_modes,
.num_items = ARRAY_SIZE(ad5624r_powerdown_modes),
.get = ad5624r_get_powerdown_mode,
.set = ad5624r_set_powerdown_mode,
};
static ssize_t ad5624r_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5624r_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
!!(st->pwr_down_mask & (1 << chan->channel)));
}
static ssize_t ad5624r_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
bool pwr_down;
int ret;
struct ad5624r_state *st = iio_priv(indio_dev);
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
if (pwr_down)
st->pwr_down_mask |= (1 << chan->channel);
else
st->pwr_down_mask &= ~(1 << chan->channel);
ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
(st->pwr_down_mode << 4) |
st->pwr_down_mask, 16);
return ret ? ret : len;
}
static const struct iio_info ad5624r_info = {
.write_raw = ad5624r_write_raw,
.read_raw = ad5624r_read_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
{
.name = "powerdown",
.read = ad5624r_read_dac_powerdown,
.write = ad5624r_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5624r_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5624r_powerdown_mode_enum),
{ },
};
#define AD5624R_CHANNEL(_chan, _bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (_chan), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 16 - (_bits), \
}, \
.ext_info = ad5624r_ext_info, \
}
#define DECLARE_AD5624R_CHANNELS(_name, _bits) \
const struct iio_chan_spec _name##_channels[] = { \
AD5624R_CHANNEL(0, _bits), \
AD5624R_CHANNEL(1, _bits), \
AD5624R_CHANNEL(2, _bits), \
AD5624R_CHANNEL(3, _bits), \
}
static DECLARE_AD5624R_CHANNELS(ad5624r, 12);
static DECLARE_AD5624R_CHANNELS(ad5644r, 14);
static DECLARE_AD5624R_CHANNELS(ad5664r, 16);
static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
[ID_AD5624R3] = {
.channels = ad5624r_channels,
.int_vref_mv = 1250,
},
[ID_AD5624R5] = {
.channels = ad5624r_channels,
.int_vref_mv = 2500,
},
[ID_AD5644R3] = {
.channels = ad5644r_channels,
.int_vref_mv = 1250,
},
[ID_AD5644R5] = {
.channels = ad5644r_channels,
.int_vref_mv = 2500,
},
[ID_AD5664R3] = {
.channels = ad5664r_channels,
.int_vref_mv = 1250,
},
[ID_AD5664R5] = {
.channels = ad5664r_channels,
.int_vref_mv = 2500,
},
};
static int ad5624r_probe(struct spi_device *spi)
{
struct ad5624r_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
spi_set_drvdata(spi, indio_dev);
st->chip_info =
&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->chip_info->int_vref_mv;
st->us = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5624r_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = AD5624R_DAC_CHANNELS;
ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
!!voltage_uv, 16);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static int ad5624r_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5624r_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad5624r_id[] = {
{"ad5624r3", ID_AD5624R3},
{"ad5644r3", ID_AD5644R3},
{"ad5664r3", ID_AD5664R3},
{"ad5624r5", ID_AD5624R5},
{"ad5644r5", ID_AD5644R5},
{"ad5664r5", ID_AD5664R5},
{}
};
MODULE_DEVICE_TABLE(spi, ad5624r_id);
static struct spi_driver ad5624r_driver = {
.driver = {
.name = "ad5624r",
.owner = THIS_MODULE,
},
.probe = ad5624r_probe,
.remove = ad5624r_remove,
.id_table = ad5624r_id,
};
module_spi_driver(ad5624r_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
MODULE_LICENSE("GPL v2");

408
drivers/iio/dac/ad5686.c Normal file
View file

@ -0,0 +1,408 @@
/*
* AD5686R, AD5685R, AD5684R Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define AD5686_DAC_CHANNELS 4
#define AD5686_ADDR(x) ((x) << 16)
#define AD5686_CMD(x) ((x) << 20)
#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
#define AD5686_ADDR_ALL_DAC 0xF
#define AD5686_CMD_NOOP 0x0
#define AD5686_CMD_WRITE_INPUT_N 0x1
#define AD5686_CMD_UPDATE_DAC_N 0x2
#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3
#define AD5686_CMD_POWERDOWN_DAC 0x4
#define AD5686_CMD_LDAC_MASK 0x5
#define AD5686_CMD_RESET 0x6
#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7
#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
#define AD5686_CMD_READBACK_ENABLE 0x9
#define AD5686_LDAC_PWRDN_NONE 0x0
#define AD5686_LDAC_PWRDN_1K 0x1
#define AD5686_LDAC_PWRDN_100K 0x2
#define AD5686_LDAC_PWRDN_3STATE 0x3
/**
* struct ad5686_chip_info - chip specific information
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @channel: channel specification
*/
struct ad5686_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[AD5686_DAC_CHANNELS];
};
/**
* struct ad5446_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @pwr_down_mask: power down mask
* @pwr_down_mode: current power down mode
* @data: spi transfer buffers
*/
struct ad5686_state {
struct spi_device *spi;
const struct ad5686_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
} data[3] ____cacheline_aligned;
};
/**
* ad5686_supported_device_ids:
*/
enum ad5686_supported_device_ids {
ID_AD5684,
ID_AD5685,
ID_AD5686,
};
static int ad5686_spi_write(struct ad5686_state *st,
u8 cmd, u8 addr, u16 val, u8 shift)
{
val <<= shift;
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr) |
val);
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
{
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[2].d8[1],
.len = 3,
},
};
int ret;
st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
AD5686_ADDR(addr));
st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
return be32_to_cpu(st->data[2].d32);
}
static const char * const ad5686_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"three_state"
};
static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5686_state *st = iio_priv(indio_dev);
return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
}
static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5686_state *st = iio_priv(indio_dev);
st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
return 0;
}
static const struct iio_enum ad5686_powerdown_mode_enum = {
.items = ad5686_powerdown_modes,
.num_items = ARRAY_SIZE(ad5686_powerdown_modes),
.get = ad5686_get_powerdown_mode,
.set = ad5686_set_powerdown_mode,
};
static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5686_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
(0x3 << (chan->channel * 2))));
}
static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
bool readin;
int ret;
struct ad5686_state *st = iio_priv(indio_dev);
ret = strtobool(buf, &readin);
if (ret)
return ret;
if (readin)
st->pwr_down_mask |= (0x3 << (chan->channel * 2));
else
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
st->pwr_down_mask & st->pwr_down_mode, 0);
return ret ? ret : len;
}
static int ad5686_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5686_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ad5686_spi_read(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ad5686_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5686_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = ad5686_spi_write(st,
AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
chan->address,
val,
chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info ad5686_info = {
.read_raw = ad5686_read_raw,
.write_raw = ad5686_write_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
{
.name = "powerdown",
.read = ad5686_read_dac_powerdown,
.write = ad5686_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum),
{ },
};
#define AD5868_CHANNEL(chan, bits, _shift) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
.address = AD5686_ADDR_DAC(chan), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = (_shift), \
}, \
.ext_info = ad5686_ext_info, \
}
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
[ID_AD5684] = {
.channel[0] = AD5868_CHANNEL(0, 12, 4),
.channel[1] = AD5868_CHANNEL(1, 12, 4),
.channel[2] = AD5868_CHANNEL(2, 12, 4),
.channel[3] = AD5868_CHANNEL(3, 12, 4),
.int_vref_mv = 2500,
},
[ID_AD5685] = {
.channel[0] = AD5868_CHANNEL(0, 14, 2),
.channel[1] = AD5868_CHANNEL(1, 14, 2),
.channel[2] = AD5868_CHANNEL(2, 14, 2),
.channel[3] = AD5868_CHANNEL(3, 14, 2),
.int_vref_mv = 2500,
},
[ID_AD5686] = {
.channel[0] = AD5868_CHANNEL(0, 16, 0),
.channel[1] = AD5868_CHANNEL(1, 16, 0),
.channel[2] = AD5868_CHANNEL(2, 16, 0),
.channel[3] = AD5868_CHANNEL(3, 16, 0),
.int_vref_mv = 2500,
},
};
static int ad5686_probe(struct spi_device *spi)
{
struct ad5686_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
st->chip_info =
&ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->chip_info->int_vref_mv;
st->spi = spi;
/* Set all the power down mode for all channels to 1K pulldown */
st->pwr_down_mode = 0x55;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5686_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = AD5686_DAC_CHANNELS;
ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
!!voltage_uv, 0);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static int ad5686_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5686_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad5686_id[] = {
{"ad5684", ID_AD5684},
{"ad5685", ID_AD5685},
{"ad5686", ID_AD5686},
{}
};
MODULE_DEVICE_TABLE(spi, ad5686_id);
static struct spi_driver ad5686_driver = {
.driver = {
.name = "ad5686",
.owner = THIS_MODULE,
},
.probe = ad5686_probe,
.remove = ad5686_remove,
.id_table = ad5686_id,
};
module_spi_driver(ad5686_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
MODULE_LICENSE("GPL v2");

622
drivers/iio/dac/ad5755.c Normal file
View file

@ -0,0 +1,622 @@
/*
* AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver
*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/ad5755.h>
#define AD5755_NUM_CHANNELS 4
#define AD5755_ADDR(x) ((x) << 16)
#define AD5755_WRITE_REG_DATA(chan) (chan)
#define AD5755_WRITE_REG_GAIN(chan) (0x08 | (chan))
#define AD5755_WRITE_REG_OFFSET(chan) (0x10 | (chan))
#define AD5755_WRITE_REG_CTRL(chan) (0x1c | (chan))
#define AD5755_READ_REG_DATA(chan) (chan)
#define AD5755_READ_REG_CTRL(chan) (0x4 | (chan))
#define AD5755_READ_REG_GAIN(chan) (0x8 | (chan))
#define AD5755_READ_REG_OFFSET(chan) (0xc | (chan))
#define AD5755_READ_REG_CLEAR(chan) (0x10 | (chan))
#define AD5755_READ_REG_SLEW(chan) (0x14 | (chan))
#define AD5755_READ_REG_STATUS 0x18
#define AD5755_READ_REG_MAIN 0x19
#define AD5755_READ_REG_DC_DC 0x1a
#define AD5755_CTRL_REG_SLEW 0x0
#define AD5755_CTRL_REG_MAIN 0x1
#define AD5755_CTRL_REG_DAC 0x2
#define AD5755_CTRL_REG_DC_DC 0x3
#define AD5755_CTRL_REG_SW 0x4
#define AD5755_READ_FLAG 0x800000
#define AD5755_NOOP 0x1CE000
#define AD5755_DAC_INT_EN BIT(8)
#define AD5755_DAC_CLR_EN BIT(7)
#define AD5755_DAC_OUT_EN BIT(6)
#define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR BIT(5)
#define AD5755_DAC_DC_DC_EN BIT(4)
#define AD5755_DAC_VOLTAGE_OVERRANGE_EN BIT(3)
#define AD5755_DC_DC_MAXV 0
#define AD5755_DC_DC_FREQ_SHIFT 2
#define AD5755_DC_DC_PHASE_SHIFT 4
#define AD5755_EXT_DC_DC_COMP_RES BIT(6)
#define AD5755_SLEW_STEP_SIZE_SHIFT 0
#define AD5755_SLEW_RATE_SHIFT 3
#define AD5755_SLEW_ENABLE BIT(12)
/**
* struct ad5755_chip_info - chip specific information
* @channel_template: channel specification
* @calib_shift: shift for the calibration data registers
* @has_voltage_out: whether the chip has voltage outputs
*/
struct ad5755_chip_info {
const struct iio_chan_spec channel_template;
unsigned int calib_shift;
bool has_voltage_out;
};
/**
* struct ad5755_state - driver instance specific data
* @spi: spi device the driver is attached to
* @chip_info: chip model specific constants, available modes etc
* @pwr_down: bitmask which contains hether a channel is powered down or not
* @ctrl: software shadow of the channel ctrl registers
* @channels: iio channel spec for the device
* @data: spi transfer buffers
*/
struct ad5755_state {
struct spi_device *spi;
const struct ad5755_chip_info *chip_info;
unsigned int pwr_down;
unsigned int ctrl[AD5755_NUM_CHANNELS];
struct iio_chan_spec channels[AD5755_NUM_CHANNELS];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
} data[2] ____cacheline_aligned;
};
enum ad5755_type {
ID_AD5755,
ID_AD5757,
ID_AD5735,
ID_AD5737,
};
static int ad5755_write_unlocked(struct iio_dev *indio_dev,
unsigned int reg, unsigned int val)
{
struct ad5755_state *st = iio_priv(indio_dev);
st->data[0].d32 = cpu_to_be32((reg << 16) | val);
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev,
unsigned int channel, unsigned int reg, unsigned int val)
{
return ad5755_write_unlocked(indio_dev,
AD5755_WRITE_REG_CTRL(channel), (reg << 13) | val);
}
static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5755_write_unlocked(indio_dev, reg, val);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel,
unsigned int reg, unsigned int val)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
{
struct ad5755_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[1].d8[1],
.len = 3,
},
};
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16));
st->data[1].d32 = cpu_to_be32(AD5755_NOOP);
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_update_dac_ctrl(struct iio_dev *indio_dev,
unsigned int channel, unsigned int set, unsigned int clr)
{
struct ad5755_state *st = iio_priv(indio_dev);
int ret;
st->ctrl[channel] |= set;
st->ctrl[channel] &= ~clr;
ret = ad5755_write_ctrl_unlocked(indio_dev, channel,
AD5755_CTRL_REG_DAC, st->ctrl[channel]);
return ret;
}
static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev,
unsigned int channel, bool pwr_down)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int mask = BIT(channel);
mutex_lock(&indio_dev->mlock);
if ((bool)(st->pwr_down & mask) == pwr_down)
goto out_unlock;
if (!pwr_down) {
st->pwr_down &= ~mask;
ad5755_update_dac_ctrl(indio_dev, channel,
AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN, 0);
udelay(200);
ad5755_update_dac_ctrl(indio_dev, channel,
AD5755_DAC_OUT_EN, 0);
} else {
st->pwr_down |= mask;
ad5755_update_dac_ctrl(indio_dev, channel,
0, AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN |
AD5755_DAC_DC_DC_EN);
}
out_unlock:
mutex_unlock(&indio_dev->mlock);
return 0;
}
static const int ad5755_min_max_table[][2] = {
[AD5755_MODE_VOLTAGE_0V_5V] = { 0, 5000 },
[AD5755_MODE_VOLTAGE_0V_10V] = { 0, 10000 },
[AD5755_MODE_VOLTAGE_PLUSMINUS_5V] = { -5000, 5000 },
[AD5755_MODE_VOLTAGE_PLUSMINUS_10V] = { -10000, 10000 },
[AD5755_MODE_CURRENT_4mA_20mA] = { 4, 20 },
[AD5755_MODE_CURRENT_0mA_20mA] = { 0, 20 },
[AD5755_MODE_CURRENT_0mA_24mA] = { 0, 24 },
};
static void ad5755_get_min_max(struct ad5755_state *st,
struct iio_chan_spec const *chan, int *min, int *max)
{
enum ad5755_mode mode = st->ctrl[chan->channel] & 7;
*min = ad5755_min_max_table[mode][0];
*max = ad5755_min_max_table[mode][1];
}
static inline int ad5755_get_offset(struct ad5755_state *st,
struct iio_chan_spec const *chan)
{
int min, max;
ad5755_get_min_max(st, chan, &min, &max);
return (min * (1 << chan->scan_type.realbits)) / (max - min);
}
static int ad5755_chan_reg_info(struct ad5755_state *st,
struct iio_chan_spec const *chan, long info, bool write,
unsigned int *reg, unsigned int *shift, unsigned int *offset)
{
switch (info) {
case IIO_CHAN_INFO_RAW:
if (write)
*reg = AD5755_WRITE_REG_DATA(chan->address);
else
*reg = AD5755_READ_REG_DATA(chan->address);
*shift = chan->scan_type.shift;
*offset = 0;
break;
case IIO_CHAN_INFO_CALIBBIAS:
if (write)
*reg = AD5755_WRITE_REG_OFFSET(chan->address);
else
*reg = AD5755_READ_REG_OFFSET(chan->address);
*shift = st->chip_info->calib_shift;
*offset = 32768;
break;
case IIO_CHAN_INFO_CALIBSCALE:
if (write)
*reg = AD5755_WRITE_REG_GAIN(chan->address);
else
*reg = AD5755_READ_REG_GAIN(chan->address);
*shift = st->chip_info->calib_shift;
*offset = 0;
break;
default:
return -EINVAL;
}
return 0;
}
static int ad5755_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int reg, shift, offset;
int min, max;
int ret;
switch (info) {
case IIO_CHAN_INFO_SCALE:
ad5755_get_min_max(st, chan, &min, &max);
*val = max - min;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
*val = ad5755_get_offset(st, chan);
return IIO_VAL_INT;
default:
ret = ad5755_chan_reg_info(st, chan, info, false,
&reg, &shift, &offset);
if (ret)
return ret;
ret = ad5755_read(indio_dev, reg);
if (ret < 0)
return ret;
*val = (ret - offset) >> shift;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad5755_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int shift, reg, offset;
int ret;
ret = ad5755_chan_reg_info(st, chan, info, true,
&reg, &shift, &offset);
if (ret)
return ret;
val <<= shift;
val += offset;
if (val < 0 || val > 0xffff)
return -EINVAL;
return ad5755_write(indio_dev, reg, val);
}
static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
const struct iio_chan_spec *chan, char *buf)
{
struct ad5755_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
(bool)(st->pwr_down & (1 << chan->channel)));
}
static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
struct iio_chan_spec const *chan, const char *buf, size_t len)
{
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
ret = ad5755_set_channel_pwr_down(indio_dev, chan->channel, pwr_down);
return ret ? ret : len;
}
static const struct iio_info ad5755_info = {
.read_raw = ad5755_read_raw,
.write_raw = ad5755_write_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
{
.name = "powerdown",
.read = ad5755_read_powerdown,
.write = ad5755_write_powerdown,
.shared = IIO_SEPARATE,
},
{ },
};
#define AD5755_CHANNEL(_bits) { \
.indexed = 1, \
.output = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 16 - (_bits), \
}, \
.ext_info = ad5755_ext_info, \
}
static const struct ad5755_chip_info ad5755_chip_info_tbl[] = {
[ID_AD5735] = {
.channel_template = AD5755_CHANNEL(14),
.has_voltage_out = true,
.calib_shift = 4,
},
[ID_AD5737] = {
.channel_template = AD5755_CHANNEL(14),
.has_voltage_out = false,
.calib_shift = 4,
},
[ID_AD5755] = {
.channel_template = AD5755_CHANNEL(16),
.has_voltage_out = true,
.calib_shift = 0,
},
[ID_AD5757] = {
.channel_template = AD5755_CHANNEL(16),
.has_voltage_out = false,
.calib_shift = 0,
},
};
static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode)
{
switch (mode) {
case AD5755_MODE_VOLTAGE_0V_5V:
case AD5755_MODE_VOLTAGE_0V_10V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
return st->chip_info->has_voltage_out;
case AD5755_MODE_CURRENT_4mA_20mA:
case AD5755_MODE_CURRENT_0mA_20mA:
case AD5755_MODE_CURRENT_0mA_24mA:
return true;
default:
return false;
}
}
static int ad5755_setup_pdata(struct iio_dev *indio_dev,
const struct ad5755_platform_data *pdata)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int val;
unsigned int i;
int ret;
if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE ||
pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ ||
pdata->dc_dc_maxv > AD5755_DC_DC_MAXV_29V5)
return -EINVAL;
val = pdata->dc_dc_maxv << AD5755_DC_DC_MAXV;
val |= pdata->dc_dc_freq << AD5755_DC_DC_FREQ_SHIFT;
val |= pdata->dc_dc_phase << AD5755_DC_DC_PHASE_SHIFT;
if (pdata->ext_dc_dc_compenstation_resistor)
val |= AD5755_EXT_DC_DC_COMP_RES;
ret = ad5755_write_ctrl(indio_dev, 0, AD5755_CTRL_REG_DC_DC, val);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
val = pdata->dac[i].slew.step_size <<
AD5755_SLEW_STEP_SIZE_SHIFT;
val |= pdata->dac[i].slew.rate <<
AD5755_SLEW_RATE_SHIFT;
if (pdata->dac[i].slew.enable)
val |= AD5755_SLEW_ENABLE;
ret = ad5755_write_ctrl(indio_dev, i,
AD5755_CTRL_REG_SLEW, val);
if (ret < 0)
return ret;
}
for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
if (!ad5755_is_valid_mode(st, pdata->dac[i].mode))
return -EINVAL;
val = 0;
if (!pdata->dac[i].ext_current_sense_resistor)
val |= AD5755_DAC_INT_CURRENT_SENSE_RESISTOR;
if (pdata->dac[i].enable_voltage_overrange)
val |= AD5755_DAC_VOLTAGE_OVERRANGE_EN;
val |= pdata->dac[i].mode;
ret = ad5755_update_dac_ctrl(indio_dev, i, val, 0);
if (ret < 0)
return ret;
}
return 0;
}
static bool ad5755_is_voltage_mode(enum ad5755_mode mode)
{
switch (mode) {
case AD5755_MODE_VOLTAGE_0V_5V:
case AD5755_MODE_VOLTAGE_0V_10V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
return true;
default:
return false;
}
}
static int ad5755_init_channels(struct iio_dev *indio_dev,
const struct ad5755_platform_data *pdata)
{
struct ad5755_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels = st->channels;
unsigned int i;
for (i = 0; i < AD5755_NUM_CHANNELS; ++i) {
channels[i] = st->chip_info->channel_template;
channels[i].channel = i;
channels[i].address = i;
if (pdata && ad5755_is_voltage_mode(pdata->dac[i].mode))
channels[i].type = IIO_VOLTAGE;
else
channels[i].type = IIO_CURRENT;
}
indio_dev->channels = channels;
return 0;
}
#define AD5755_DEFAULT_DAC_PDATA { \
.mode = AD5755_MODE_CURRENT_4mA_20mA, \
.ext_current_sense_resistor = true, \
.enable_voltage_overrange = false, \
.slew = { \
.enable = false, \
.rate = AD5755_SLEW_RATE_64k, \
.step_size = AD5755_SLEW_STEP_SIZE_1, \
}, \
}
static const struct ad5755_platform_data ad5755_default_pdata = {
.ext_dc_dc_compenstation_resistor = false,
.dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE,
.dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ,
.dc_dc_maxv = AD5755_DC_DC_MAXV_23V,
.dac = {
[0] = AD5755_DEFAULT_DAC_PDATA,
[1] = AD5755_DEFAULT_DAC_PDATA,
[2] = AD5755_DEFAULT_DAC_PDATA,
[3] = AD5755_DEFAULT_DAC_PDATA,
},
};
static int ad5755_probe(struct spi_device *spi)
{
enum ad5755_type type = spi_get_device_id(spi)->driver_data;
const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5755_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->chip_info = &ad5755_chip_info_tbl[type];
st->spi = spi;
st->pwr_down = 0xf;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5755_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5755_NUM_CHANNELS;
if (!pdata)
pdata = &ad5755_default_pdata;
ret = ad5755_init_channels(indio_dev, pdata);
if (ret)
return ret;
ret = ad5755_setup_pdata(indio_dev, pdata);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad5755_id[] = {
{ "ad5755", ID_AD5755 },
{ "ad5755-1", ID_AD5755 },
{ "ad5757", ID_AD5757 },
{ "ad5735", ID_AD5735 },
{ "ad5737", ID_AD5737 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5755_id);
static struct spi_driver ad5755_driver = {
.driver = {
.name = "ad5755",
.owner = THIS_MODULE,
},
.probe = ad5755_probe,
.id_table = ad5755_id,
};
module_spi_driver(ad5755_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5755/55-1/57/35/37 DAC");
MODULE_LICENSE("GPL v2");

370
drivers/iio/dac/ad5764.c Normal file
View file

@ -0,0 +1,370 @@
/*
* Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel
* Digital to Analog Converters driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define AD5764_REG_SF_NOP 0x0
#define AD5764_REG_SF_CONFIG 0x1
#define AD5764_REG_SF_CLEAR 0x4
#define AD5764_REG_SF_LOAD 0x5
#define AD5764_REG_DATA(x) ((2 << 3) | (x))
#define AD5764_REG_COARSE_GAIN(x) ((3 << 3) | (x))
#define AD5764_REG_FINE_GAIN(x) ((4 << 3) | (x))
#define AD5764_REG_OFFSET(x) ((5 << 3) | (x))
#define AD5764_NUM_CHANNELS 4
/**
* struct ad5764_chip_info - chip specific information
* @int_vref: Value of the internal reference voltage in uV - 0 if external
* reference voltage is used
* @channel channel specification
*/
struct ad5764_chip_info {
unsigned long int_vref;
const struct iio_chan_spec *channels;
};
/**
* struct ad5764_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip info
* @vref_reg: vref supply regulators
* @data: spi transfer buffers
*/
struct ad5764_state {
struct spi_device *spi;
const struct ad5764_chip_info *chip_info;
struct regulator_bulk_data vref_reg[2];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
} data[2] ____cacheline_aligned;
};
enum ad5764_type {
ID_AD5744,
ID_AD5744R,
ID_AD5764,
ID_AD5764R,
};
#define AD5764_CHANNEL(_chan, _bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 16 - (_bits), \
}, \
}
#define DECLARE_AD5764_CHANNELS(_name, _bits) \
const struct iio_chan_spec _name##_channels[] = { \
AD5764_CHANNEL(0, (_bits)), \
AD5764_CHANNEL(1, (_bits)), \
AD5764_CHANNEL(2, (_bits)), \
AD5764_CHANNEL(3, (_bits)), \
};
static DECLARE_AD5764_CHANNELS(ad5764, 16);
static DECLARE_AD5764_CHANNELS(ad5744, 14);
static const struct ad5764_chip_info ad5764_chip_infos[] = {
[ID_AD5744] = {
.int_vref = 0,
.channels = ad5744_channels,
},
[ID_AD5744R] = {
.int_vref = 5000000,
.channels = ad5744_channels,
},
[ID_AD5764] = {
.int_vref = 0,
.channels = ad5764_channels,
},
[ID_AD5764R] = {
.int_vref = 5000000,
.channels = ad5764_channels,
},
};
static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
struct ad5764_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32((reg << 16) | val);
ret = spi_write(st->spi, &st->data[0].d8[1], 3);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
unsigned int *val)
{
struct ad5764_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.rx_buf = &st->data[1].d8[1],
.len = 3,
},
};
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
*val = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info)
{
switch (info) {
case 0:
return AD5764_REG_DATA(chan->address);
case IIO_CHAN_INFO_CALIBBIAS:
return AD5764_REG_OFFSET(chan->address);
case IIO_CHAN_INFO_CALIBSCALE:
return AD5764_REG_FINE_GAIN(chan->address);
default:
break;
}
return 0;
}
static int ad5764_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
const int max_val = (1 << chan->scan_type.realbits);
unsigned int reg;
switch (info) {
case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
break;
case IIO_CHAN_INFO_CALIBBIAS:
if (val >= 128 || val < -128)
return -EINVAL;
break;
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= 32 || val < -32)
return -EINVAL;
break;
default:
return -EINVAL;
}
reg = ad5764_chan_info_to_reg(chan, info);
return ad5764_write(indio_dev, reg, (u16)val);
}
static int ad5764_get_channel_vref(struct ad5764_state *st,
unsigned int channel)
{
if (st->chip_info->int_vref)
return st->chip_info->int_vref;
else
return regulator_get_voltage(st->vref_reg[channel / 2].consumer);
}
static int ad5764_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct ad5764_state *st = iio_priv(indio_dev);
unsigned int reg;
int vref;
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
reg = AD5764_REG_DATA(chan->address);
ret = ad5764_read(indio_dev, reg, val);
if (ret < 0)
return ret;
*val >>= chan->scan_type.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
reg = AD5764_REG_OFFSET(chan->address);
ret = ad5764_read(indio_dev, reg, val);
if (ret < 0)
return ret;
*val = sign_extend32(*val, 7);
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
reg = AD5764_REG_FINE_GAIN(chan->address);
ret = ad5764_read(indio_dev, reg, val);
if (ret < 0)
return ret;
*val = sign_extend32(*val, 5);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* vout = 4 * vref + ((dac_code / 65536) - 0.5) */
vref = ad5764_get_channel_vref(st, chan->channel);
if (vref < 0)
return vref;
*val = vref * 4 / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
*val = -(1 << chan->scan_type.realbits) / 2;
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info ad5764_info = {
.read_raw = ad5764_read_raw,
.write_raw = ad5764_write_raw,
.driver_module = THIS_MODULE,
};
static int ad5764_probe(struct spi_device *spi)
{
enum ad5764_type type = spi_get_device_id(spi)->driver_data;
struct iio_dev *indio_dev;
struct ad5764_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->chip_info = &ad5764_chip_infos[type];
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5764_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5764_NUM_CHANNELS;
indio_dev->channels = st->chip_info->channels;
if (st->chip_info->int_vref == 0) {
st->vref_reg[0].supply = "vrefAB";
st->vref_reg[1].supply = "vrefCD";
ret = devm_regulator_bulk_get(&st->spi->dev,
ARRAY_SIZE(st->vref_reg), st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
ret);
return ret;
}
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
goto error_disable_reg;
}
return 0;
error_disable_reg:
if (st->chip_info->int_vref == 0)
regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
return ret;
}
static int ad5764_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5764_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (st->chip_info->int_vref == 0)
regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
return 0;
}
static const struct spi_device_id ad5764_ids[] = {
{ "ad5744", ID_AD5744 },
{ "ad5744r", ID_AD5744R },
{ "ad5764", ID_AD5764 },
{ "ad5764r", ID_AD5764R },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5764_ids);
static struct spi_driver ad5764_driver = {
.driver = {
.name = "ad5764",
.owner = THIS_MODULE,
},
.probe = ad5764_probe,
.remove = ad5764_remove,
.id_table = ad5764_ids,
};
module_spi_driver(ad5764_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC");
MODULE_LICENSE("GPL v2");

474
drivers/iio/dac/ad5791.c Normal file
View file

@ -0,0 +1,474 @@
/*
* AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog
* Converter
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/dac/ad5791.h>
#define AD5791_DAC_MASK GENMASK(19, 0)
#define AD5791_CMD_READ BIT(23)
#define AD5791_CMD_WRITE 0
#define AD5791_ADDR(addr) ((addr) << 20)
/* Registers */
#define AD5791_ADDR_NOOP 0
#define AD5791_ADDR_DAC0 1
#define AD5791_ADDR_CTRL 2
#define AD5791_ADDR_CLRCODE 3
#define AD5791_ADDR_SW_CTRL 4
/* Control Register */
#define AD5791_CTRL_RBUF BIT(1)
#define AD5791_CTRL_OPGND BIT(2)
#define AD5791_CTRL_DACTRI BIT(3)
#define AD5791_CTRL_BIN2SC BIT(4)
#define AD5791_CTRL_SDODIS BIT(5)
#define AD5761_CTRL_LINCOMP(x) ((x) << 6)
#define AD5791_LINCOMP_0_10 0
#define AD5791_LINCOMP_10_12 1
#define AD5791_LINCOMP_12_16 2
#define AD5791_LINCOMP_16_19 3
#define AD5791_LINCOMP_19_20 12
#define AD5780_LINCOMP_0_10 0
#define AD5780_LINCOMP_10_20 12
/* Software Control Register */
#define AD5791_SWCTRL_LDAC BIT(0)
#define AD5791_SWCTRL_CLR BIT(1)
#define AD5791_SWCTRL_RESET BIT(2)
#define AD5791_DAC_PWRDN_6K 0
#define AD5791_DAC_PWRDN_3STATE 1
/**
* struct ad5791_chip_info - chip specific information
* @get_lin_comp: function pointer to the device specific function
*/
struct ad5791_chip_info {
int (*get_lin_comp) (unsigned int span);
};
/**
* struct ad5791_state - driver instance specific data
* @spi: spi_device
* @reg_vdd: positive supply regulator
* @reg_vss: negative supply regulator
* @chip_info: chip model specific constants
* @vref_mv: actual reference voltage used
* @vref_neg_mv: voltage of the negative supply
* @pwr_down_mode current power down mode
*/
struct ad5791_state {
struct spi_device *spi;
struct regulator *reg_vdd;
struct regulator *reg_vss;
const struct ad5791_chip_info *chip_info;
unsigned short vref_mv;
unsigned int vref_neg_mv;
unsigned ctrl;
unsigned pwr_down_mode;
bool pwr_down;
union {
__be32 d32;
u8 d8[4];
} data[3] ____cacheline_aligned;
};
/**
* ad5791_supported_device_ids:
*/
enum ad5791_supported_device_ids {
ID_AD5760,
ID_AD5780,
ID_AD5781,
ID_AD5791,
};
static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val)
{
st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE |
AD5791_ADDR(addr) |
(val & AD5791_DAC_MASK));
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5791_spi_read(struct ad5791_state *st, u8 addr, u32 *val)
{
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = &st->data[0].d8[1],
.bits_per_word = 8,
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[2].d8[1],
.bits_per_word = 8,
.len = 3,
},
};
st->data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
AD5791_ADDR(addr));
st->data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
*val = be32_to_cpu(st->data[2].d32);
return ret;
}
static const char * const ad5791_powerdown_modes[] = {
"6kohm_to_gnd",
"three_state",
};
static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5791_state *st = iio_priv(indio_dev);
return st->pwr_down_mode;
}
static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5791_state *st = iio_priv(indio_dev);
st->pwr_down_mode = mode;
return 0;
}
static const struct iio_enum ad5791_powerdown_mode_enum = {
.items = ad5791_powerdown_modes,
.num_items = ARRAY_SIZE(ad5791_powerdown_modes),
.get = ad5791_get_powerdown_mode,
.set = ad5791_set_powerdown_mode,
};
static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5791_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
bool pwr_down;
int ret;
struct ad5791_state *st = iio_priv(indio_dev);
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
if (!pwr_down) {
st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
} else {
if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
st->ctrl |= AD5791_CTRL_OPGND;
else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
st->ctrl |= AD5791_CTRL_DACTRI;
}
st->pwr_down = pwr_down;
ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl);
return ret ? ret : len;
}
static int ad5791_get_lin_comp(unsigned int span)
{
if (span <= 10000)
return AD5791_LINCOMP_0_10;
else if (span <= 12000)
return AD5791_LINCOMP_10_12;
else if (span <= 16000)
return AD5791_LINCOMP_12_16;
else if (span <= 19000)
return AD5791_LINCOMP_16_19;
else
return AD5791_LINCOMP_19_20;
}
static int ad5780_get_lin_comp(unsigned int span)
{
if (span <= 10000)
return AD5780_LINCOMP_0_10;
else
return AD5780_LINCOMP_10_20;
}
static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
[ID_AD5760] = {
.get_lin_comp = ad5780_get_lin_comp,
},
[ID_AD5780] = {
.get_lin_comp = ad5780_get_lin_comp,
},
[ID_AD5781] = {
.get_lin_comp = ad5791_get_lin_comp,
},
[ID_AD5791] = {
.get_lin_comp = ad5791_get_lin_comp,
},
};
static int ad5791_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5791_state *st = iio_priv(indio_dev);
u64 val64;
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5791_spi_read(st, chan->address, val);
if (ret)
return ret;
*val &= AD5791_DAC_MASK;
*val >>= chan->scan_type.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = (1 << chan->scan_type.realbits) - 1;
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_OFFSET:
val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
do_div(val64, st->vref_mv);
*val = -val64;
return IIO_VAL_INT;
default:
return -EINVAL;
}
};
static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
{
.name = "powerdown",
.shared = IIO_SHARED_BY_TYPE,
.read = ad5791_read_dac_powerdown,
.write = ad5791_write_dac_powerdown,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5791_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum),
{ },
};
#define AD5791_CHAN(bits, _shift) { \
.type = IIO_VOLTAGE, \
.output = 1, \
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 24, \
.shift = (_shift), \
}, \
.ext_info = ad5791_ext_info, \
}
static const struct iio_chan_spec ad5791_channels[] = {
[ID_AD5760] = AD5791_CHAN(16, 4),
[ID_AD5780] = AD5791_CHAN(18, 2),
[ID_AD5781] = AD5791_CHAN(18, 2),
[ID_AD5791] = AD5791_CHAN(20, 0)
};
static int ad5791_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5791_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
val &= GENMASK(chan->scan_type.realbits - 1, 0);
val <<= chan->scan_type.shift;
return ad5791_spi_write(st, chan->address, val);
default:
return -EINVAL;
}
}
static const struct iio_info ad5791_info = {
.read_raw = &ad5791_read_raw,
.write_raw = &ad5791_write_raw,
.driver_module = THIS_MODULE,
};
static int ad5791_probe(struct spi_device *spi)
{
struct ad5791_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
if (!IS_ERR(st->reg_vdd)) {
ret = regulator_enable(st->reg_vdd);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg_vdd);
if (ret < 0)
goto error_disable_reg_pos;
pos_voltage_uv = ret;
}
st->reg_vss = devm_regulator_get(&spi->dev, "vss");
if (!IS_ERR(st->reg_vss)) {
ret = regulator_enable(st->reg_vss);
if (ret)
goto error_disable_reg_pos;
ret = regulator_get_voltage(st->reg_vss);
if (ret < 0)
goto error_disable_reg_neg;
neg_voltage_uv = ret;
}
st->pwr_down = true;
st->spi = spi;
if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
st->vref_neg_mv = neg_voltage_uv / 1000;
} else if (pdata) {
st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
st->vref_neg_mv = pdata->vref_neg_mv;
} else {
dev_warn(&spi->dev, "reference voltage unspecified\n");
}
ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
if (ret)
goto error_disable_reg_neg;
st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi)
->driver_data];
st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
| ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
AD5791_CTRL_BIN2SC;
ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl |
AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
if (ret)
goto error_disable_reg_neg;
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad5791_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels
= &ad5791_channels[spi_get_device_id(spi)->driver_data];
indio_dev->num_channels = 1;
indio_dev->name = spi_get_device_id(st->spi)->name;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg_neg;
return 0;
error_disable_reg_neg:
if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
error_disable_reg_pos:
if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
return ret;
}
static int ad5791_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5791_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
return 0;
}
static const struct spi_device_id ad5791_id[] = {
{"ad5760", ID_AD5760},
{"ad5780", ID_AD5780},
{"ad5781", ID_AD5781},
{"ad5790", ID_AD5791},
{"ad5791", ID_AD5791},
{}
};
MODULE_DEVICE_TABLE(spi, ad5791_id);
static struct spi_driver ad5791_driver = {
.driver = {
.name = "ad5791",
.owner = THIS_MODULE,
},
.probe = ad5791_probe,
.remove = ad5791_remove,
.id_table = ad5791_id,
};
module_spi_driver(ad5791_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
MODULE_LICENSE("GPL v2");

303
drivers/iio/dac/ad7303.c Normal file
View file

@ -0,0 +1,303 @@
/*
* AD7303 Digital to analog converters driver
*
* Copyright 2013 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/ad7303.h>
#define AD7303_CFG_EXTERNAL_VREF BIT(15)
#define AD7303_CFG_POWER_DOWN(ch) BIT(11 + (ch))
#define AD7303_CFG_ADDR_OFFSET 10
#define AD7303_CMD_UPDATE_DAC (0x3 << 8)
/**
* struct ad7303_state - driver instance specific data
* @spi: the device for this driver instance
* @config: cached config register value
* @dac_cache: current DAC raw value (chip does not support readback)
* @data: spi transfer buffer
*/
struct ad7303_state {
struct spi_device *spi;
uint16_t config;
uint8_t dac_cache[2];
struct regulator *vdd_reg;
struct regulator *vref_reg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 data ____cacheline_aligned;
};
static int ad7303_write(struct ad7303_state *st, unsigned int chan,
uint8_t val)
{
st->data = cpu_to_be16(AD7303_CMD_UPDATE_DAC |
(chan << AD7303_CFG_ADDR_OFFSET) |
st->config | val);
return spi_write(st->spi, &st->data, sizeof(st->data));
}
static ssize_t ad7303_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad7303_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", (bool)(st->config &
AD7303_CFG_POWER_DOWN(chan->channel)));
}
static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
struct ad7303_state *st = iio_priv(indio_dev);
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
if (pwr_down)
st->config |= AD7303_CFG_POWER_DOWN(chan->channel);
else
st->config &= ~AD7303_CFG_POWER_DOWN(chan->channel);
/* There is no noop cmd which allows us to only update the powerdown
* mode, so just write one of the DAC channels again */
ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
mutex_unlock(&indio_dev->mlock);
return len;
}
static int ad7303_get_vref(struct ad7303_state *st,
struct iio_chan_spec const *chan)
{
int ret;
if (st->config & AD7303_CFG_EXTERNAL_VREF)
return regulator_get_voltage(st->vref_reg);
ret = regulator_get_voltage(st->vdd_reg);
if (ret < 0)
return ret;
return ret / 2;
}
static int ad7303_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct ad7303_state *st = iio_priv(indio_dev);
int vref_uv;
switch (info) {
case IIO_CHAN_INFO_RAW:
*val = st->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
vref_uv = ad7303_get_vref(st, chan);
if (vref_uv < 0)
return vref_uv;
*val = 2 * vref_uv / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static int ad7303_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct ad7303_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = ad7303_write(st, chan->address, val);
if (ret == 0)
st->dac_cache[chan->channel] = val;
mutex_unlock(&indio_dev->mlock);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info ad7303_info = {
.read_raw = ad7303_read_raw,
.write_raw = ad7303_write_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad7303_ext_info[] = {
{
.name = "powerdown",
.read = ad7303_read_dac_powerdown,
.write = ad7303_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
{ },
};
#define AD7303_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (chan), \
.scan_type = { \
.sign = 'u', \
.realbits = '8', \
.storagebits = '8', \
.shift = '0', \
}, \
.ext_info = ad7303_ext_info, \
}
static const struct iio_chan_spec ad7303_channels[] = {
AD7303_CHANNEL(0),
AD7303_CHANNEL(1),
};
static int ad7303_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct ad7303_state *st;
bool ext_ref;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
if (IS_ERR(st->vdd_reg))
return PTR_ERR(st->vdd_reg);
ret = regulator_enable(st->vdd_reg);
if (ret)
return ret;
if (spi->dev.of_node) {
ext_ref = of_property_read_bool(spi->dev.of_node,
"REF-supply");
} else {
struct ad7303_platform_data *pdata = spi->dev.platform_data;
if (pdata && pdata->use_external_ref)
ext_ref = true;
else
ext_ref = false;
}
if (ext_ref) {
st->vref_reg = devm_regulator_get(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
goto err_disable_vdd_reg;
}
ret = regulator_enable(st->vref_reg);
if (ret)
goto err_disable_vdd_reg;
st->config |= AD7303_CFG_EXTERNAL_VREF;
}
indio_dev->dev.parent = &spi->dev;
indio_dev->name = id->name;
indio_dev->info = &ad7303_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad7303_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7303_channels);
ret = iio_device_register(indio_dev);
if (ret)
goto err_disable_vref_reg;
return 0;
err_disable_vref_reg:
if (st->vref_reg)
regulator_disable(st->vref_reg);
err_disable_vdd_reg:
regulator_disable(st->vdd_reg);
return ret;
}
static int ad7303_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7303_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (st->vref_reg)
regulator_disable(st->vref_reg);
regulator_disable(st->vdd_reg);
return 0;
}
static const struct spi_device_id ad7303_spi_ids[] = {
{ "ad7303", 0 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
static struct spi_driver ad7303_driver = {
.driver = {
.name = "ad7303",
.owner = THIS_MODULE,
},
.probe = ad7303_probe,
.remove = ad7303_remove,
.id_table = ad7303_spi_ids,
};
module_spi_driver(ad7303_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD7303 DAC driver");
MODULE_LICENSE("GPL v2");

222
drivers/iio/dac/max517.c Normal file
View file

@ -0,0 +1,222 @@
/*
* max517.c - Support for Maxim MAX517, MAX518 and MAX519
*
* Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/dac/max517.h>
#define MAX517_DRV_NAME "max517"
/* Commands */
#define COMMAND_CHANNEL0 0x00
#define COMMAND_CHANNEL1 0x01 /* for MAX518 and MAX519 */
#define COMMAND_PD 0x08 /* Power Down */
enum max517_device_ids {
ID_MAX517,
ID_MAX518,
ID_MAX519,
};
struct max517_data {
struct i2c_client *client;
unsigned short vref_mv[2];
};
/*
* channel: bit 0: channel 1
* bit 1: channel 2
* (this way, it's possible to set both channels at once)
*/
static int max517_set_value(struct iio_dev *indio_dev,
long val, int channel)
{
struct max517_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[2];
int res;
if (val < 0 || val > 255)
return -EINVAL;
outbuf[0] = channel;
outbuf[1] = val;
res = i2c_master_send(client, outbuf, 2);
if (res < 0)
return res;
else if (res != 2)
return -EIO;
else
return 0;
}
static int max517_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct max517_data *data = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
/* Corresponds to Vref / 2^(bits) */
*val = data->vref_mv[chan->channel];
*val2 = 8;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static int max517_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = max517_set_value(indio_dev, val, chan->channel);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int max517_suspend(struct device *dev)
{
u8 outbuf = COMMAND_PD;
return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
}
static int max517_resume(struct device *dev)
{
u8 outbuf = 0;
return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
}
static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
#define MAX517_PM_OPS (&max517_pm_ops)
#else
#define MAX517_PM_OPS NULL
#endif
static const struct iio_info max517_info = {
.read_raw = max517_read_raw,
.write_raw = max517_write_raw,
.driver_module = THIS_MODULE,
};
#define MAX517_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec max517_channels[] = {
MAX517_CHANNEL(0),
MAX517_CHANNEL(1)
};
static int max517_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max517_data *data;
struct iio_dev *indio_dev;
struct max517_platform_data *platform_data = client->dev.platform_data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
/* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
/* reduced channel set for MAX517 */
if (id->driver_data == ID_MAX517)
indio_dev->num_channels = 1;
else
indio_dev->num_channels = 2;
indio_dev->channels = max517_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &max517_info;
/*
* Reference voltage on MAX518 and default is 5V, else take vref_mv
* from platform_data
*/
if (id->driver_data == ID_MAX518 || !platform_data) {
data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
} else {
data->vref_mv[0] = platform_data->vref_mv[0];
data->vref_mv[1] = platform_data->vref_mv[1];
}
return iio_device_register(indio_dev);
}
static int max517_remove(struct i2c_client *client)
{
iio_device_unregister(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id max517_id[] = {
{ "max517", ID_MAX517 },
{ "max518", ID_MAX518 },
{ "max519", ID_MAX519 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max517_id);
static struct i2c_driver max517_driver = {
.driver = {
.name = MAX517_DRV_NAME,
.pm = MAX517_PM_OPS,
},
.probe = max517_probe,
.remove = max517_remove,
.id_table = max517_id,
};
module_i2c_driver(max517_driver);
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
MODULE_LICENSE("GPL");

405
drivers/iio/dac/max5821.c Normal file
View file

@ -0,0 +1,405 @@
/*
* iio/dac/max5821.c
* Copyright (C) 2014 Philippe Reynes
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#define MAX5821_MAX_DAC_CHANNELS 2
/* command bytes */
#define MAX5821_LOAD_DAC_A_IN_REG_B 0x00
#define MAX5821_LOAD_DAC_B_IN_REG_A 0x10
#define MAX5821_EXTENDED_COMMAND_MODE 0xf0
#define MAX5821_READ_DAC_A_COMMAND 0xf1
#define MAX5821_READ_DAC_B_COMMAND 0xf2
#define MAX5821_EXTENDED_POWER_UP 0x00
#define MAX5821_EXTENDED_POWER_DOWN_MODE0 0x01
#define MAX5821_EXTENDED_POWER_DOWN_MODE1 0x02
#define MAX5821_EXTENDED_POWER_DOWN_MODE2 0x03
#define MAX5821_EXTENDED_DAC_A 0x04
#define MAX5821_EXTENDED_DAC_B 0x08
enum max5821_device_ids {
ID_MAX5821,
};
struct max5821_data {
struct i2c_client *client;
struct regulator *vref_reg;
unsigned short vref_mv;
bool powerdown[MAX5821_MAX_DAC_CHANNELS];
u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS];
struct mutex lock;
};
static const char * const max5821_powerdown_modes[] = {
"three_state",
"1kohm_to_gnd",
"100kohm_to_gnd",
};
enum {
MAX5821_THREE_STATE,
MAX5821_1KOHM_TO_GND,
MAX5821_100KOHM_TO_GND
};
static int max5821_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct max5821_data *st = iio_priv(indio_dev);
return st->powerdown_mode[chan->channel];
}
static int max5821_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int mode)
{
struct max5821_data *st = iio_priv(indio_dev);
st->powerdown_mode[chan->channel] = mode;
return 0;
}
static const struct iio_enum max5821_powerdown_mode_enum = {
.items = max5821_powerdown_modes,
.num_items = ARRAY_SIZE(max5821_powerdown_modes),
.get = max5821_get_powerdown_mode,
.set = max5821_set_powerdown_mode,
};
static ssize_t max5821_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct max5821_data *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->powerdown[chan->channel]);
}
static int max5821_sync_powerdown_mode(struct max5821_data *data,
const struct iio_chan_spec *chan)
{
u8 outbuf[2];
outbuf[0] = MAX5821_EXTENDED_COMMAND_MODE;
if (chan->channel == 0)
outbuf[1] = MAX5821_EXTENDED_DAC_A;
else
outbuf[1] = MAX5821_EXTENDED_DAC_B;
if (data->powerdown[chan->channel])
outbuf[1] |= data->powerdown_mode[chan->channel] + 1;
else
outbuf[1] |= MAX5821_EXTENDED_POWER_UP;
return i2c_master_send(data->client, outbuf, 2);
}
static ssize_t max5821_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct max5821_data *data = iio_priv(indio_dev);
bool powerdown;
int ret;
ret = strtobool(buf, &powerdown);
if (ret)
return ret;
data->powerdown[chan->channel] = powerdown;
ret = max5821_sync_powerdown_mode(data, chan);
if (ret < 0)
return ret;
return len;
}
static const struct iio_chan_spec_ext_info max5821_ext_info[] = {
{
.name = "powerdown",
.read = max5821_read_dac_powerdown,
.write = max5821_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &max5821_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &max5821_powerdown_mode_enum),
{ },
};
#define MAX5821_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = max5821_ext_info, \
}
static const struct iio_chan_spec max5821_channels[] = {
MAX5821_CHANNEL(0),
MAX5821_CHANNEL(1)
};
static const u8 max5821_read_dac_command[] = {
MAX5821_READ_DAC_A_COMMAND,
MAX5821_READ_DAC_B_COMMAND
};
static const u8 max5821_load_dac_command[] = {
MAX5821_LOAD_DAC_A_IN_REG_B,
MAX5821_LOAD_DAC_B_IN_REG_A
};
static int max5821_get_value(struct iio_dev *indio_dev,
int *val, int channel)
{
struct max5821_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[1];
u8 inbuf[2];
int ret;
if ((channel != 0) && (channel != 1))
return -EINVAL;
outbuf[0] = max5821_read_dac_command[channel];
mutex_lock(&data->lock);
ret = i2c_master_send(client, outbuf, 1);
if (ret < 0) {
mutex_unlock(&data->lock);
return ret;
} else if (ret != 1) {
mutex_unlock(&data->lock);
return -EIO;
}
ret = i2c_master_recv(client, inbuf, 2);
if (ret < 0) {
mutex_unlock(&data->lock);
return ret;
} else if (ret != 2) {
mutex_unlock(&data->lock);
return -EIO;
}
mutex_unlock(&data->lock);
*val = ((inbuf[0] & 0x0f) << 6) | (inbuf[1] >> 2);
return IIO_VAL_INT;
}
static int max5821_set_value(struct iio_dev *indio_dev,
int val, int channel)
{
struct max5821_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[2];
int ret;
if ((val < 0) || (val > 1023))
return -EINVAL;
if ((channel != 0) && (channel != 1))
return -EINVAL;
outbuf[0] = max5821_load_dac_command[channel];
outbuf[0] |= val >> 6;
outbuf[1] = (val & 0x3f) << 2;
ret = i2c_master_send(client, outbuf, 2);
if (ret < 0)
return ret;
else if (ret != 2)
return -EIO;
else
return 0;
}
static int max5821_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct max5821_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
return max5821_get_value(indio_dev, val, chan->channel);
case IIO_CHAN_INFO_SCALE:
*val = data->vref_mv;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static int max5821_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
return max5821_set_value(indio_dev, val, chan->channel);
default:
return -EINVAL;
}
}
#ifdef CONFIG_PM_SLEEP
static int max5821_suspend(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
MAX5821_EXTENDED_DAC_B |
MAX5821_EXTENDED_POWER_DOWN_MODE2 };
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
static int max5821_resume(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
MAX5821_EXTENDED_DAC_B |
MAX5821_EXTENDED_POWER_UP };
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume);
#define MAX5821_PM_OPS (&max5821_pm_ops)
#else
#define MAX5821_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static const struct iio_info max5821_info = {
.read_raw = max5821_read_raw,
.write_raw = max5821_write_raw,
.driver_module = THIS_MODULE,
};
static int max5821_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max5821_data *data;
struct iio_dev *indio_dev;
u32 tmp;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
/* max5821 start in powerdown mode 100Kohm to ground */
for (tmp = 0; tmp < MAX5821_MAX_DAC_CHANNELS; tmp++) {
data->powerdown[tmp] = true;
data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND;
}
data->vref_reg = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(data->vref_reg)) {
ret = PTR_ERR(data->vref_reg);
dev_err(&client->dev,
"Failed to get vref regulator: %d\n", ret);
goto error_free_reg;
}
ret = regulator_enable(data->vref_reg);
if (ret) {
dev_err(&client->dev,
"Failed to enable vref regulator: %d\n", ret);
goto error_free_reg;
}
ret = regulator_get_voltage(data->vref_reg);
if (ret < 0) {
dev_err(&client->dev,
"Failed to get voltage on regulator: %d\n", ret);
goto error_disable_reg;
}
data->vref_mv = ret / 1000;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->num_channels = ARRAY_SIZE(max5821_channels);
indio_dev->channels = max5821_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &max5821_info;
return iio_device_register(indio_dev);
error_disable_reg:
regulator_disable(data->vref_reg);
error_free_reg:
return ret;
}
static int max5821_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct max5821_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(data->vref_reg);
return 0;
}
static const struct i2c_device_id max5821_id[] = {
{ "max5821", ID_MAX5821 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max5821_id);
static const struct of_device_id max5821_of_match[] = {
{ .compatible = "maxim,max5821" },
{ }
};
static struct i2c_driver max5821_driver = {
.driver = {
.name = "max5821",
.pm = MAX5821_PM_OPS,
.owner = THIS_MODULE,
},
.probe = max5821_probe,
.remove = max5821_remove,
.id_table = max5821_id,
};
module_i2c_driver(max5821_driver);
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
MODULE_DESCRIPTION("MAX5821 DAC");
MODULE_LICENSE("GPL v2");

349
drivers/iio/dac/mcp4725.c Normal file
View file

@ -0,0 +1,349 @@
/*
* mcp4725.c - Support for Microchip MCP4725
*
* Copyright (C) 2012 Peter Meerwald <pmeerw@pmeerw.net>
*
* Based on max517 by Roland Stigge <stigge@antcom.de>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* driver for the Microchip I2C 12-bit digital-to-analog converter (DAC)
* (7-bit I2C slave address 0x60, the three LSBs can be configured in
* hardware)
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/dac/mcp4725.h>
#define MCP4725_DRV_NAME "mcp4725"
struct mcp4725_data {
struct i2c_client *client;
u16 vref_mv;
u16 dac_value;
bool powerdown;
unsigned powerdown_mode;
};
static int mcp4725_suspend(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
u8 outbuf[2];
outbuf[0] = (data->powerdown_mode + 1) << 4;
outbuf[1] = 0;
data->powerdown = true;
return i2c_master_send(data->client, outbuf, 2);
}
static int mcp4725_resume(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
u8 outbuf[2];
/* restore previous DAC value */
outbuf[0] = (data->dac_value >> 8) & 0xf;
outbuf[1] = data->dac_value & 0xff;
data->powerdown = false;
return i2c_master_send(data->client, outbuf, 2);
}
#ifdef CONFIG_PM_SLEEP
static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
#define MCP4725_PM_OPS (&mcp4725_pm_ops)
#else
#define MCP4725_PM_OPS NULL
#endif
static ssize_t mcp4725_store_eeprom(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct mcp4725_data *data = iio_priv(indio_dev);
int tries = 20;
u8 inoutbuf[3];
bool state;
int ret;
ret = strtobool(buf, &state);
if (ret < 0)
return ret;
if (!state)
return 0;
inoutbuf[0] = 0x60; /* write EEPROM */
inoutbuf[1] = data->dac_value >> 4;
inoutbuf[2] = (data->dac_value & 0xf) << 4;
ret = i2c_master_send(data->client, inoutbuf, 3);
if (ret < 0)
return ret;
else if (ret != 3)
return -EIO;
/* wait for write complete, takes up to 50ms */
while (tries--) {
msleep(20);
ret = i2c_master_recv(data->client, inoutbuf, 3);
if (ret < 0)
return ret;
else if (ret != 3)
return -EIO;
if (inoutbuf[0] & 0x80)
break;
}
if (tries < 0) {
dev_err(&data->client->dev,
"mcp4725_store_eeprom() failed, incomplete\n");
return -EIO;
}
return len;
}
static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR, NULL, mcp4725_store_eeprom, 0);
static struct attribute *mcp4725_attributes[] = {
&iio_dev_attr_store_eeprom.dev_attr.attr,
NULL,
};
static const struct attribute_group mcp4725_attribute_group = {
.attrs = mcp4725_attributes,
};
static const char * const mcp4725_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"500kohm_to_gnd"
};
static int mcp4725_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct mcp4725_data *data = iio_priv(indio_dev);
return data->powerdown_mode;
}
static int mcp4725_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned mode)
{
struct mcp4725_data *data = iio_priv(indio_dev);
data->powerdown_mode = mode;
return 0;
}
static ssize_t mcp4725_read_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct mcp4725_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->powerdown);
}
static ssize_t mcp4725_write_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct mcp4725_data *data = iio_priv(indio_dev);
bool state;
int ret;
ret = strtobool(buf, &state);
if (ret)
return ret;
if (state)
ret = mcp4725_suspend(&data->client->dev);
else
ret = mcp4725_resume(&data->client->dev);
if (ret < 0)
return ret;
return len;
}
static const struct iio_enum mcp4725_powerdown_mode_enum = {
.items = mcp4725_powerdown_modes,
.num_items = ARRAY_SIZE(mcp4725_powerdown_modes),
.get = mcp4725_get_powerdown_mode,
.set = mcp4725_set_powerdown_mode,
};
static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = {
{
.name = "powerdown",
.read = mcp4725_read_powerdown,
.write = mcp4725_write_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4725_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &mcp4725_powerdown_mode_enum),
{ },
};
static const struct iio_chan_spec mcp4725_channel = {
.type = IIO_VOLTAGE,
.indexed = 1,
.output = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.ext_info = mcp4725_ext_info,
};
static int mcp4725_set_value(struct iio_dev *indio_dev, int val)
{
struct mcp4725_data *data = iio_priv(indio_dev);
u8 outbuf[2];
int ret;
if (val >= (1 << 12) || val < 0)
return -EINVAL;
outbuf[0] = (val >> 8) & 0xf;
outbuf[1] = val & 0xff;
ret = i2c_master_send(data->client, outbuf, 2);
if (ret < 0)
return ret;
else if (ret != 2)
return -EIO;
else
return 0;
}
static int mcp4725_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mcp4725_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = data->dac_value;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = data->vref_mv;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int mcp4725_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mcp4725_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = mcp4725_set_value(indio_dev, val);
data->dac_value = val;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct iio_info mcp4725_info = {
.read_raw = mcp4725_read_raw,
.write_raw = mcp4725_write_raw,
.attrs = &mcp4725_attribute_group,
.driver_module = THIS_MODULE,
};
static int mcp4725_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mcp4725_data *data;
struct iio_dev *indio_dev;
struct mcp4725_platform_data *platform_data = client->dev.platform_data;
u8 inbuf[3];
u8 pd;
int err;
if (!platform_data || !platform_data->vref_mv) {
dev_err(&client->dev, "invalid platform data");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (indio_dev == NULL)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &mcp4725_info;
indio_dev->channels = &mcp4725_channel;
indio_dev->num_channels = 1;
indio_dev->modes = INDIO_DIRECT_MODE;
data->vref_mv = platform_data->vref_mv;
/* read current DAC value */
err = i2c_master_recv(client, inbuf, 3);
if (err < 0) {
dev_err(&client->dev, "failed to read DAC value");
return err;
}
pd = (inbuf[0] >> 1) & 0x3;
data->powerdown = pd > 0 ? true : false;
data->powerdown_mode = pd ? pd-1 : 2; /* 500kohm_to_gnd */
data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
return iio_device_register(indio_dev);
}
static int mcp4725_remove(struct i2c_client *client)
{
iio_device_unregister(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id mcp4725_id[] = {
{ "mcp4725", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp4725_id);
static struct i2c_driver mcp4725_driver = {
.driver = {
.name = MCP4725_DRV_NAME,
.pm = MCP4725_PM_OPS,
},
.probe = mcp4725_probe,
.remove = mcp4725_remove,
.id_table = mcp4725_id,
};
module_i2c_driver(mcp4725_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("MCP4725 12-bit DAC");
MODULE_LICENSE("GPL");

216
drivers/iio/dac/mcp4922.c Normal file
View file

@ -0,0 +1,216 @@
/*
* mcp4922.c
*
* Driver for Microchip Digital to Analog Converters.
* Supports MCP4902, MCP4912, and MCP4922.
*
* Copyright (c) 2014 EMAC Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/bitops.h>
#define MCP4922_NUM_CHANNELS 2
enum mcp4922_supported_device_ids {
ID_MCP4902,
ID_MCP4912,
ID_MCP4922,
};
struct mcp4922_state {
struct spi_device *spi;
unsigned int value[MCP4922_NUM_CHANNELS];
unsigned int vref_mv;
struct regulator *vref_reg;
u8 mosi[2] ____cacheline_aligned;
};
#define MCP4922_CHAN(chan, bits) { \
.type = IIO_VOLTAGE, \
.output = 1, \
.indexed = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = 12 - (bits), \
}, \
}
static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val)
{
state->mosi[1] = val & 0xff;
state->mosi[0] = (addr == 0) ? 0x00 : 0x80;
state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f);
return spi_write(state->spi, state->mosi, 2);
}
static int mcp4922_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct mcp4922_state *state = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = state->value[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = state->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static int mcp4922_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct mcp4922_state *state = iio_priv(indio_dev);
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val > GENMASK(chan->scan_type.realbits-1, 0))
return -EINVAL;
val <<= chan->scan_type.shift;
state->value[chan->channel] = val;
return mcp4922_spi_write(state, chan->channel, val);
default:
return -EINVAL;
}
}
static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = {
[ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) },
[ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) },
[ID_MCP4922] = { MCP4922_CHAN(0, 12), MCP4922_CHAN(1, 12) },
};
static const struct iio_info mcp4922_info = {
.read_raw = &mcp4922_read_raw,
.write_raw = &mcp4922_write_raw,
.driver_module = THIS_MODULE,
};
static int mcp4922_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mcp4922_state *state;
const struct spi_device_id *id;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
if (indio_dev == NULL)
return -ENOMEM;
state = iio_priv(indio_dev);
state->spi = spi;
state->vref_reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(state->vref_reg)) {
dev_err(&spi->dev, "Vref regulator not specified\n");
return PTR_ERR(state->vref_reg);
}
ret = regulator_enable(state->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vref regulator: %d\n",
ret);
return ret;
}
ret = regulator_get_voltage(state->vref_reg);
if (ret < 0) {
dev_err(&spi->dev, "Failed to read vref regulator: %d\n",
ret);
goto error_disable_reg;
}
state->vref_mv = ret / 1000;
spi_set_drvdata(spi, indio_dev);
id = spi_get_device_id(spi);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &mcp4922_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mcp4922_channels[id->driver_data];
indio_dev->num_channels = MCP4922_NUM_CHANNELS;
indio_dev->name = id->name;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n",
ret);
goto error_disable_reg;
}
return 0;
error_disable_reg:
regulator_disable(state->vref_reg);
return ret;
}
static int mcp4922_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct mcp4922_state *state;
iio_device_unregister(indio_dev);
state = iio_priv(indio_dev);
regulator_disable(state->vref_reg);
return 0;
}
static const struct spi_device_id mcp4922_id[] = {
{"mcp4902", ID_MCP4902},
{"mcp4912", ID_MCP4912},
{"mcp4922", ID_MCP4922},
{}
};
MODULE_DEVICE_TABLE(spi, mcp4922_id);
static struct spi_driver mcp4922_driver = {
.driver = {
.name = "mcp4922",
.owner = THIS_MODULE,
},
.probe = mcp4922_probe,
.remove = mcp4922_remove,
.id_table = mcp4922_id,
};
module_spi_driver(mcp4922_driver);
MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,42 @@
#
# Frequency
# Direct Digital Synthesis drivers (DDS)
# Clock Distribution device drivers
# Phase-Locked Loop (PLL) frequency synthesizers
#
# When adding new entries keep the list in alphabetical order
menu "Frequency Synthesizers DDS/PLL"
menu "Clock Generator/Distribution"
config AD9523
tristate "Analog Devices AD9523 Low Jitter Clock Generator"
depends on SPI
help
Say yes here to build support for Analog Devices AD9523 Low Jitter
Clock Generator. The driver provides direct access via sysfs.
To compile this driver as a module, choose M here: the
module will be called ad9523.
endmenu
#
# Phase-Locked Loop (PLL) frequency synthesizers
#
menu "Phase-Locked Loop (PLL) frequency synthesizers"
config ADF4350
tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers"
depends on SPI
help
Say yes here to build support for Analog Devices ADF4350/ADF4351
Wideband Synthesizers. The driver provides direct access via sysfs.
To compile this driver as a module, choose M here: the
module will be called adf4350.
endmenu
endmenu

View file

@ -0,0 +1,7 @@
#
# Makefile iio/frequency
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,642 @@
/*
* ADF4350/ADF4351 SPI Wideband Synthesizer driver
*
* Copyright 2012-2013 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gcd.h>
#include <linux/gpio.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/frequency/adf4350.h>
enum {
ADF4350_FREQ,
ADF4350_FREQ_REFIN,
ADF4350_FREQ_RESOLUTION,
ADF4350_PWRDOWN,
};
struct adf4350_state {
struct spi_device *spi;
struct regulator *reg;
struct adf4350_platform_data *pdata;
struct clk *clk;
unsigned long clkin;
unsigned long chspc; /* Channel Spacing */
unsigned long fpfd; /* Phase Frequency Detector */
unsigned long min_out_freq;
unsigned r0_fract;
unsigned r0_int;
unsigned r1_mod;
unsigned r4_rf_div_sel;
unsigned long regs[6];
unsigned long regs_hw[6];
unsigned long long freq_req;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be32 val ____cacheline_aligned;
};
static struct adf4350_platform_data default_pdata = {
.channel_spacing = 10000,
.r2_user_settings = ADF4350_REG2_PD_POLARITY_POS |
ADF4350_REG2_CHARGE_PUMP_CURR_uA(2500),
.r3_user_settings = ADF4350_REG3_12BIT_CLKDIV_MODE(0),
.r4_user_settings = ADF4350_REG4_OUTPUT_PWR(3) |
ADF4350_REG4_MUTE_TILL_LOCK_EN,
.gpio_lock_detect = -1,
};
static int adf4350_sync_config(struct adf4350_state *st)
{
int ret, i, doublebuf = 0;
for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) {
if ((st->regs_hw[i] != st->regs[i]) ||
((i == ADF4350_REG0) && doublebuf)) {
switch (i) {
case ADF4350_REG1:
case ADF4350_REG4:
doublebuf = 1;
break;
}
st->val = cpu_to_be32(st->regs[i] | i);
ret = spi_write(st->spi, &st->val, 4);
if (ret < 0)
return ret;
st->regs_hw[i] = st->regs[i];
dev_dbg(&st->spi->dev, "[%d] 0x%X\n",
i, (u32)st->regs[i] | i);
}
}
return 0;
}
static int adf4350_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct adf4350_state *st = iio_priv(indio_dev);
int ret;
if (reg > ADF4350_REG5)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
if (readval == NULL) {
st->regs[reg] = writeval & ~(BIT(0) | BIT(1) | BIT(2));
ret = adf4350_sync_config(st);
} else {
*readval = st->regs_hw[reg];
ret = 0;
}
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int adf4350_tune_r_cnt(struct adf4350_state *st, unsigned short r_cnt)
{
struct adf4350_platform_data *pdata = st->pdata;
do {
r_cnt++;
st->fpfd = (st->clkin * (pdata->ref_doubler_en ? 2 : 1)) /
(r_cnt * (pdata->ref_div2_en ? 2 : 1));
} while (st->fpfd > ADF4350_MAX_FREQ_PFD);
return r_cnt;
}
static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
{
struct adf4350_platform_data *pdata = st->pdata;
u64 tmp;
u32 div_gcd, prescaler, chspc;
u16 mdiv, r_cnt = 0;
u8 band_sel_div;
if (freq > ADF4350_MAX_OUT_FREQ || freq < st->min_out_freq)
return -EINVAL;
if (freq > ADF4350_MAX_FREQ_45_PRESC) {
prescaler = ADF4350_REG1_PRESCALER;
mdiv = 75;
} else {
prescaler = 0;
mdiv = 23;
}
st->r4_rf_div_sel = 0;
while (freq < ADF4350_MIN_VCO_FREQ) {
freq <<= 1;
st->r4_rf_div_sel++;
}
/*
* Allow a predefined reference division factor
* if not set, compute our own
*/
if (pdata->ref_div_factor)
r_cnt = pdata->ref_div_factor - 1;
chspc = st->chspc;
do {
do {
do {
r_cnt = adf4350_tune_r_cnt(st, r_cnt);
st->r1_mod = st->fpfd / chspc;
if (r_cnt > ADF4350_MAX_R_CNT) {
/* try higher spacing values */
chspc++;
r_cnt = 0;
}
} while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
} while (r_cnt == 0);
tmp = freq * (u64)st->r1_mod + (st->fpfd >> 1);
do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
st->r0_fract = do_div(tmp, st->r1_mod);
st->r0_int = tmp;
} while (mdiv > st->r0_int);
band_sel_div = DIV_ROUND_UP(st->fpfd, ADF4350_MAX_BANDSEL_CLK);
if (st->r0_fract && st->r1_mod) {
div_gcd = gcd(st->r1_mod, st->r0_fract);
st->r1_mod /= div_gcd;
st->r0_fract /= div_gcd;
} else {
st->r0_fract = 0;
st->r1_mod = 1;
}
dev_dbg(&st->spi->dev, "VCO: %llu Hz, PFD %lu Hz\n"
"REF_DIV %d, R0_INT %d, R0_FRACT %d\n"
"R1_MOD %d, RF_DIV %d\nPRESCALER %s, BAND_SEL_DIV %d\n",
freq, st->fpfd, r_cnt, st->r0_int, st->r0_fract, st->r1_mod,
1 << st->r4_rf_div_sel, prescaler ? "8/9" : "4/5",
band_sel_div);
st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
ADF4350_REG0_FRACT(st->r0_fract);
st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) |
ADF4350_REG1_MOD(st->r1_mod) |
prescaler;
st->regs[ADF4350_REG2] =
ADF4350_REG2_10BIT_R_CNT(r_cnt) |
ADF4350_REG2_DOUBLE_BUFF_EN |
(pdata->ref_doubler_en ? ADF4350_REG2_RMULT2_EN : 0) |
(pdata->ref_div2_en ? ADF4350_REG2_RDIV2_EN : 0) |
(pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS |
ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N |
ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) |
ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x3)));
st->regs[ADF4350_REG3] = pdata->r3_user_settings &
(ADF4350_REG3_12BIT_CLKDIV(0xFFF) |
ADF4350_REG3_12BIT_CLKDIV_MODE(0x3) |
ADF4350_REG3_12BIT_CSR_EN |
ADF4351_REG3_CHARGE_CANCELLATION_EN |
ADF4351_REG3_ANTI_BACKLASH_3ns_EN |
ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH);
st->regs[ADF4350_REG4] =
ADF4350_REG4_FEEDBACK_FUND |
ADF4350_REG4_RF_DIV_SEL(st->r4_rf_div_sel) |
ADF4350_REG4_8BIT_BAND_SEL_CLKDIV(band_sel_div) |
ADF4350_REG4_RF_OUT_EN |
(pdata->r4_user_settings &
(ADF4350_REG4_OUTPUT_PWR(0x3) |
ADF4350_REG4_AUX_OUTPUT_PWR(0x3) |
ADF4350_REG4_AUX_OUTPUT_EN |
ADF4350_REG4_AUX_OUTPUT_FUND |
ADF4350_REG4_MUTE_TILL_LOCK_EN));
st->regs[ADF4350_REG5] = ADF4350_REG5_LD_PIN_MODE_DIGITAL;
st->freq_req = freq;
return adf4350_sync_config(st);
}
static ssize_t adf4350_write(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct adf4350_state *st = iio_priv(indio_dev);
unsigned long long readin;
unsigned long tmp;
int ret;
ret = kstrtoull(buf, 10, &readin);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
switch ((u32)private) {
case ADF4350_FREQ:
ret = adf4350_set_freq(st, readin);
break;
case ADF4350_FREQ_REFIN:
if (readin > ADF4350_MAX_FREQ_REFIN) {
ret = -EINVAL;
break;
}
if (st->clk) {
tmp = clk_round_rate(st->clk, readin);
if (tmp != readin) {
ret = -EINVAL;
break;
}
ret = clk_set_rate(st->clk, tmp);
if (ret < 0)
break;
}
st->clkin = readin;
ret = adf4350_set_freq(st, st->freq_req);
break;
case ADF4350_FREQ_RESOLUTION:
if (readin == 0)
ret = -EINVAL;
else
st->chspc = readin;
break;
case ADF4350_PWRDOWN:
if (readin)
st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
else
st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN;
adf4350_sync_config(st);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static ssize_t adf4350_read(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct adf4350_state *st = iio_priv(indio_dev);
unsigned long long val;
int ret = 0;
mutex_lock(&indio_dev->mlock);
switch ((u32)private) {
case ADF4350_FREQ:
val = (u64)((st->r0_int * st->r1_mod) + st->r0_fract) *
(u64)st->fpfd;
do_div(val, st->r1_mod * (1 << st->r4_rf_div_sel));
/* PLL unlocked? return error */
if (gpio_is_valid(st->pdata->gpio_lock_detect))
if (!gpio_get_value(st->pdata->gpio_lock_detect)) {
dev_dbg(&st->spi->dev, "PLL un-locked\n");
ret = -EBUSY;
}
break;
case ADF4350_FREQ_REFIN:
if (st->clk)
st->clkin = clk_get_rate(st->clk);
val = st->clkin;
break;
case ADF4350_FREQ_RESOLUTION:
val = st->chspc;
break;
case ADF4350_PWRDOWN:
val = !!(st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN);
break;
default:
ret = -EINVAL;
val = 0;
}
mutex_unlock(&indio_dev->mlock);
return ret < 0 ? ret : sprintf(buf, "%llu\n", val);
}
#define _ADF4350_EXT_INFO(_name, _ident) { \
.name = _name, \
.read = adf4350_read, \
.write = adf4350_write, \
.private = _ident, \
.shared = IIO_SEPARATE, \
}
static const struct iio_chan_spec_ext_info adf4350_ext_info[] = {
/* Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are
* values > 2^32 in order to support the entire frequency range
* in Hz. Using scale is a bit ugly.
*/
_ADF4350_EXT_INFO("frequency", ADF4350_FREQ),
_ADF4350_EXT_INFO("frequency_resolution", ADF4350_FREQ_RESOLUTION),
_ADF4350_EXT_INFO("refin_frequency", ADF4350_FREQ_REFIN),
_ADF4350_EXT_INFO("powerdown", ADF4350_PWRDOWN),
{ },
};
static const struct iio_chan_spec adf4350_chan = {
.type = IIO_ALTVOLTAGE,
.indexed = 1,
.output = 1,
.ext_info = adf4350_ext_info,
};
static const struct iio_info adf4350_info = {
.debugfs_reg_access = &adf4350_reg_access,
.driver_module = THIS_MODULE,
};
#ifdef CONFIG_OF
static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct adf4350_platform_data *pdata;
unsigned int tmp;
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "could not allocate memory for platform data\n");
return NULL;
}
strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
tmp = 10000;
of_property_read_u32(np, "adi,channel-spacing", &tmp);
pdata->channel_spacing = tmp;
tmp = 0;
of_property_read_u32(np, "adi,power-up-frequency", &tmp);
pdata->power_up_frequency = tmp;
tmp = 0;
of_property_read_u32(np, "adi,reference-div-factor", &tmp);
pdata->ref_div_factor = tmp;
ret = of_get_gpio(np, 0);
if (ret < 0)
pdata->gpio_lock_detect = -1;
else
pdata->gpio_lock_detect = ret;
pdata->ref_doubler_en = of_property_read_bool(np,
"adi,reference-doubler-enable");
pdata->ref_div2_en = of_property_read_bool(np,
"adi,reference-div2-enable");
/* r2_user_settings */
pdata->r2_user_settings = of_property_read_bool(np,
"adi,phase-detector-polarity-positive-enable") ?
ADF4350_REG2_PD_POLARITY_POS : 0;
pdata->r2_user_settings |= of_property_read_bool(np,
"adi,lock-detect-precision-6ns-enable") ?
ADF4350_REG2_LDP_6ns : 0;
pdata->r2_user_settings |= of_property_read_bool(np,
"adi,lock-detect-function-integer-n-enable") ?
ADF4350_REG2_LDF_INT_N : 0;
tmp = 2500;
of_property_read_u32(np, "adi,charge-pump-current", &tmp);
pdata->r2_user_settings |= ADF4350_REG2_CHARGE_PUMP_CURR_uA(tmp);
tmp = 0;
of_property_read_u32(np, "adi,muxout-select", &tmp);
pdata->r2_user_settings |= ADF4350_REG2_MUXOUT(tmp);
pdata->r2_user_settings |= of_property_read_bool(np,
"adi,low-spur-mode-enable") ?
ADF4350_REG2_NOISE_MODE(0x3) : 0;
/* r3_user_settings */
pdata->r3_user_settings = of_property_read_bool(np,
"adi,cycle-slip-reduction-enable") ?
ADF4350_REG3_12BIT_CSR_EN : 0;
pdata->r3_user_settings |= of_property_read_bool(np,
"adi,charge-cancellation-enable") ?
ADF4351_REG3_CHARGE_CANCELLATION_EN : 0;
pdata->r3_user_settings |= of_property_read_bool(np,
"adi,anti-backlash-3ns-enable") ?
ADF4351_REG3_ANTI_BACKLASH_3ns_EN : 0;
pdata->r3_user_settings |= of_property_read_bool(np,
"adi,band-select-clock-mode-high-enable") ?
ADF4351_REG3_BAND_SEL_CLOCK_MODE_HIGH : 0;
tmp = 0;
of_property_read_u32(np, "adi,12bit-clk-divider", &tmp);
pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV(tmp);
tmp = 0;
of_property_read_u32(np, "adi,clk-divider-mode", &tmp);
pdata->r3_user_settings |= ADF4350_REG3_12BIT_CLKDIV_MODE(tmp);
/* r4_user_settings */
pdata->r4_user_settings = of_property_read_bool(np,
"adi,aux-output-enable") ?
ADF4350_REG4_AUX_OUTPUT_EN : 0;
pdata->r4_user_settings |= of_property_read_bool(np,
"adi,aux-output-fundamental-enable") ?
ADF4350_REG4_AUX_OUTPUT_FUND : 0;
pdata->r4_user_settings |= of_property_read_bool(np,
"adi,mute-till-lock-enable") ?
ADF4350_REG4_MUTE_TILL_LOCK_EN : 0;
tmp = 0;
of_property_read_u32(np, "adi,output-power", &tmp);
pdata->r4_user_settings |= ADF4350_REG4_OUTPUT_PWR(tmp);
tmp = 0;
of_property_read_u32(np, "adi,aux-output-power", &tmp);
pdata->r4_user_settings |= ADF4350_REG4_AUX_OUTPUT_PWR(tmp);
return pdata;
}
#else
static
struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
{
return NULL;
}
#endif
static int adf4350_probe(struct spi_device *spi)
{
struct adf4350_platform_data *pdata;
struct iio_dev *indio_dev;
struct adf4350_state *st;
struct clk *clk = NULL;
int ret;
if (spi->dev.of_node) {
pdata = adf4350_parse_dt(&spi->dev);
if (pdata == NULL)
return -EINVAL;
} else {
pdata = spi->dev.platform_data;
}
if (!pdata) {
dev_warn(&spi->dev, "no platform data? using default\n");
pdata = &default_pdata;
}
if (!pdata->clkin) {
clk = devm_clk_get(&spi->dev, "clkin");
if (IS_ERR(clk))
return -EPROBE_DEFER;
ret = clk_prepare_enable(clk);
if (ret < 0)
return ret;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_clk;
}
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
goto error_disable_clk;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->pdata = pdata;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = (pdata->name[0] != 0) ? pdata->name :
spi_get_device_id(spi)->name;
indio_dev->info = &adf4350_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &adf4350_chan;
indio_dev->num_channels = 1;
st->chspc = pdata->channel_spacing;
if (clk) {
st->clk = clk;
st->clkin = clk_get_rate(clk);
} else {
st->clkin = pdata->clkin;
}
st->min_out_freq = spi_get_device_id(spi)->driver_data == 4351 ?
ADF4351_MIN_OUT_FREQ : ADF4350_MIN_OUT_FREQ;
memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
if (gpio_is_valid(pdata->gpio_lock_detect)) {
ret = devm_gpio_request(&spi->dev, pdata->gpio_lock_detect,
indio_dev->name);
if (ret) {
dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
pdata->gpio_lock_detect);
goto error_disable_reg;
}
gpio_direction_input(pdata->gpio_lock_detect);
}
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);
if (ret)
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
error_disable_clk:
if (clk)
clk_disable_unprepare(clk);
return ret;
}
static int adf4350_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adf4350_state *st = iio_priv(indio_dev);
struct regulator *reg = st->reg;
st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
adf4350_sync_config(st);
iio_device_unregister(indio_dev);
if (st->clk)
clk_disable_unprepare(st->clk);
if (!IS_ERR(reg)) {
regulator_disable(reg);
}
return 0;
}
static const struct spi_device_id adf4350_id[] = {
{"adf4350", 4350},
{"adf4351", 4351},
{}
};
static struct spi_driver adf4350_driver = {
.driver = {
.name = "adf4350",
.owner = THIS_MODULE,
},
.probe = adf4350_probe,
.remove = adf4350_remove,
.id_table = adf4350_id,
};
module_spi_driver(adf4350_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADF4350/ADF4351 PLL");
MODULE_LICENSE("GPL v2");

112
drivers/iio/gyro/Kconfig Normal file
View file

@ -0,0 +1,112 @@
#
# IIO Digital Gyroscope Sensor drivers configuration
#
# When adding new entries keep the list in alphabetical order
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 ADIS16130
tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADIS16130 High Precision
Angular Rate Sensor driver.
config ADIS16136
tristate "Analog devices ADIS16136 and similar gyroscopes driver"
depends on SPI_MASTER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
config ADIS16260
tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor 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 ADIS16260 ADIS16265
ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
This driver can also be built as a module. If so, the module
will be called adis16260.
config ADXRS450
tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADXRS450 and ADXRS453
programmable digital output gyroscope.
This driver can also be built as a module. If so, the module
will be called adxrs450.
config BMG160
tristate "BOSCH BMG160 Gyro Sensor"
depends on I2C
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
help
Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
driver. This driver also supports BMI055 gyroscope.
This driver can also be built as a module. If so, the module
will be called bmg160.
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
select HID_SENSOR_IIO_TRIGGER
tristate "HID Gyroscope 3D"
help
Say yes here to build support for the HID SENSOR
Gyroscope 3D.
config IIO_ST_GYRO_3AXIS
tristate "STMicroelectronics gyroscopes 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
select IIO_ST_SENSORS_CORE
select IIO_ST_GYRO_I2C_3AXIS if (I2C)
select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER)
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics gyroscopes:
L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
This driver can also be built as a module. If so, these modules
will be created:
- st_gyro (core functions for the driver [it is mandatory]);
- st_gyro_i2c (necessary for the I2C devices [optional*]);
- st_gyro_spi (necessary for the SPI devices [optional*]);
(*) one of these is necessary to do something.
config IIO_ST_GYRO_I2C_3AXIS
tristate
depends on IIO_ST_GYRO_3AXIS
depends on IIO_ST_SENSORS_I2C
config IIO_ST_GYRO_SPI_3AXIS
tristate
depends on IIO_ST_GYRO_3AXIS
depends on IIO_ST_SENSORS_SPI
config ITG3200
tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver"
depends on I2C
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
help
Say yes here to add support for the InvenSense ITG3200 digital
3-axis gyroscope sensor.
endmenu

24
drivers/iio/gyro/Makefile Normal file
View file

@ -0,0 +1,24 @@
#
# Makefile for industrial I/O gyroscope sensor drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADIS16080) += adis16080.o
obj-$(CONFIG_ADIS16130) += adis16130.o
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_ADIS16260) += adis16260.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
obj-$(CONFIG_BMG160) += bmg160.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
itg3200-y := itg3200_core.o
itg3200-$(CONFIG_IIO_BUFFER) += itg3200_buffer.o
obj-$(CONFIG_ITG3200) += itg3200.o
obj-$(CONFIG_IIO_ST_GYRO_3AXIS) += st_gyro.o
st_gyro-y := st_gyro_core.o
st_gyro-$(CONFIG_IIO_BUFFER) += st_gyro_buffer.o
obj-$(CONFIG_IIO_ST_GYRO_I2C_3AXIS) += st_gyro_i2c.o
obj-$(CONFIG_IIO_ST_GYRO_SPI_3AXIS) += st_gyro_spi.o

View file

@ -0,0 +1,241 @@
/*
* ADIS16080/100 Yaw Rate Gyroscope with SPI driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
#define ADIS16080_DIN_AIN1 (2 << 10)
#define ADIS16080_DIN_AIN2 (3 << 10)
/*
* 1: Write contents on DIN to control register.
* 0: No changes to control register.
*/
#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;
};
static int adis16080_read_sample(struct iio_dev *indio_dev,
u16 addr, int *val)
{
struct adis16080_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->buf,
.len = 2,
.cs_change = 1,
}, {
.rx_buf = &st->buf,
.len = 2,
},
};
st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE);
ret = spi_sync_transfer(st->us, t, ARRAY_SIZE(t));
if (ret == 0)
*val = sign_extend32(be16_to_cpu(st->buf), 11);
return ret;
}
static int adis16080_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct adis16080_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
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;
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;
}
static const struct iio_chan_spec adis16080_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_TEMP,
}
};
static const struct iio_info adis16080_info = {
.read_raw = &adis16080_read_raw,
.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);
struct adis16080_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
/* 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;
indio_dev->num_channels = ARRAY_SIZE(adis16080_channels);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16080_info;
indio_dev->modes = INDIO_DIRECT_MODE;
return iio_device_register(indio_dev);
}
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
return 0;
}
static const struct spi_device_id adis16080_ids[] = {
{ "adis16080", ID_ADIS16080 },
{ "adis16100", ID_ADIS16100 },
{},
};
MODULE_DEVICE_TABLE(spi, adis16080_ids);
static struct spi_driver adis16080_driver = {
.driver = {
.name = "adis16080",
.owner = THIS_MODULE,
},
.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");

View file

@ -0,0 +1,179 @@
/*
* ADIS16130 Digital Output, High Precision Angular Rate Sensor driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#define ADIS16130_CON 0x0
#define ADIS16130_CON_RD (1 << 6)
#define ADIS16130_IOP 0x1
/* 1 = data-ready signal low when unread data on all channels; */
#define ADIS16130_IOP_ALL_RDY (1 << 3)
#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
#define ADIS16130_TEMPDATA 0xA /* Temperature output */
#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
#define ADIS16130_TEMPCS_EN (1 << 3)
#define ADIS16130_RATECONV 0x30
#define ADIS16130_TEMPCONV 0x32
#define ADIS16130_MODE 0x38
#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
/**
* struct adis16130_state - device instance specific data
* @us: actual spi_device to write data
* @buf_lock: mutex to protect tx and rx
* @buf: unified tx/rx buffer
**/
struct adis16130_state {
struct spi_device *us;
struct mutex buf_lock;
u8 buf[4] ____cacheline_aligned;
};
static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val)
{
int ret;
struct adis16130_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->buf,
.rx_buf = st->buf,
.len = 4,
};
mutex_lock(&st->buf_lock);
st->buf[0] = ADIS16130_CON_RD | reg_addr;
st->buf[1] = st->buf[2] = st->buf[3] = 0;
ret = spi_sync_transfer(st->us, &xfer, 1);
if (ret == 0)
*val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3];
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16130_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
int ret;
u32 temp;
switch (mask) {
case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
ret = adis16130_spi_read(indio_dev, chan->address, &temp);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
*val = temp;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
/* 0 degree = 838860, 250 degree = 14260608 */
*val = 250;
*val2 = 336440817; /* RAD_TO_DEGREE(14260608 - 8388608) */
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
/* 0C = 8036283, 105C = 9516048 */
*val = 105000;
*val2 = 9516048 - 8036283;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = -8388608;
return IIO_VAL_INT;
case IIO_TEMP:
*val = -8036283;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static const struct iio_chan_spec adis16130_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16130_RATEDATA,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16130_TEMPDATA,
}
};
static const struct iio_info adis16130_info = {
.read_raw = &adis16130_read_raw,
.driver_module = THIS_MODULE,
};
static int adis16130_probe(struct spi_device *spi)
{
struct adis16130_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->channels = adis16130_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16130_channels);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16130_info;
indio_dev->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static struct spi_driver adis16130_driver = {
.driver = {
.name = "adis16130",
.owner = THIS_MODULE,
},
.probe = adis16130_probe,
};
module_spi_driver(adis16130_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:adis16130");

View file

@ -0,0 +1,577 @@
/*
* ADIS16133/ADIS16135/ADIS16136 gyroscope driver
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/debugfs.h>
#define ADIS16136_REG_FLASH_CNT 0x00
#define ADIS16136_REG_TEMP_OUT 0x02
#define ADIS16136_REG_GYRO_OUT2 0x04
#define ADIS16136_REG_GYRO_OUT 0x06
#define ADIS16136_REG_GYRO_OFF2 0x08
#define ADIS16136_REG_GYRO_OFF 0x0A
#define ADIS16136_REG_ALM_MAG1 0x10
#define ADIS16136_REG_ALM_MAG2 0x12
#define ADIS16136_REG_ALM_SAMPL1 0x14
#define ADIS16136_REG_ALM_SAMPL2 0x16
#define ADIS16136_REG_ALM_CTRL 0x18
#define ADIS16136_REG_GPIO_CTRL 0x1A
#define ADIS16136_REG_MSC_CTRL 0x1C
#define ADIS16136_REG_SMPL_PRD 0x1E
#define ADIS16136_REG_AVG_CNT 0x20
#define ADIS16136_REG_DEC_RATE 0x22
#define ADIS16136_REG_SLP_CTRL 0x24
#define ADIS16136_REG_DIAG_STAT 0x26
#define ADIS16136_REG_GLOB_CMD 0x28
#define ADIS16136_REG_LOT1 0x32
#define ADIS16136_REG_LOT2 0x34
#define ADIS16136_REG_LOT3 0x36
#define ADIS16136_REG_PROD_ID 0x38
#define ADIS16136_REG_SERIAL_NUM 0x3A
#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2
#define ADIS16136_DIAG_STAT_SPI_FAIL 3
#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5
#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6
#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11)
#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10)
struct adis16136_chip_info {
unsigned int precision;
unsigned int fullscale;
};
struct adis16136 {
const struct adis16136_chip_info *chip_info;
struct adis adis;
};
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16136_show_serial(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
struct adis16136 *adis16136 = file->private_data;
uint16_t lot1, lot2, lot3, serial;
char buf[20];
size_t len;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
&serial);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
if (ret < 0)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
lot3, serial);
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
static const struct file_operations adis16136_serial_fops = {
.open = simple_open,
.read = adis16136_show_serial,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static int adis16136_show_product_id(void *arg, u64 *val)
{
struct adis16136 *adis16136 = arg;
u16 prod_id;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
if (ret < 0)
return ret;
*val = prod_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops,
adis16136_show_product_id, NULL, "%llu\n");
static int adis16136_show_flash_count(void *arg, u64 *val)
{
struct adis16136 *adis16136 = arg;
uint16_t flash_count;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
return ret;
*val = flash_count;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops,
adis16136_show_flash_count, NULL, "%lld\n");
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_serial_fops);
debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_product_id_fops);
debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_flash_count_fops);
return 0;
}
#else
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
return 0;
}
#endif
static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
{
unsigned int t;
t = 32768 / freq;
if (t < 0xf)
t = 0xf;
else if (t > 0xffff)
t = 0xffff;
else
t--;
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
}
static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
{
uint16_t t;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
if (ret < 0)
return ret;
*freq = 32768 / (t + 1);
return 0;
}
static ssize_t adis16136_write_frequency(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int val;
int ret;
ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
if (val == 0)
return -EINVAL;
ret = adis16136_set_freq(adis16136, val);
return ret ? ret : len;
}
static ssize_t adis16136_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
int ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16136_read_frequency,
adis16136_write_frequency);
static const unsigned adis16136_3db_divisors[] = {
[0] = 2, /* Special case */
[1] = 6,
[2] = 12,
[3] = 25,
[4] = 50,
[5] = 100,
[6] = 200,
[7] = 200, /* Not a valid setting */
};
static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
int i, ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
uint16_t val16;
int ret;
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
if (ret < 0)
goto err_unlock;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
goto err_unlock;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
mutex_unlock(&indio_dev->mlock);
return ret ? ret : IIO_VAL_INT;
}
static int adis16136_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
uint32_t val32;
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = adis16136->chip_info->precision;
*val2 = (adis16136->chip_info->fullscale << 16);
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
*val = 10;
*val2 = 697000; /* 0.010697 degree Celsius */
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, &val32);
if (ret < 0)
return ret;
*val = sign_extend32(val32, 31);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16136_get_filter(indio_dev, val);
default:
return -EINVAL;
}
}
static int adis16136_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
return adis_write_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16136_set_filter(indio_dev, val);
default:
break;
}
return -EINVAL;
}
enum {
ADIS16136_SCAN_GYRO,
ADIS16136_SCAN_TEMP,
};
static const struct iio_chan_spec adis16136_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16136_REG_GYRO_OUT2,
.scan_index = ADIS16136_SCAN_GYRO,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16136_REG_TEMP_OUT,
.scan_index = ADIS16136_SCAN_TEMP,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static struct attribute *adis16136_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
NULL
};
static const struct attribute_group adis16136_attribute_group = {
.attrs = adis16136_attributes,
};
static const struct iio_info adis16136_info = {
.driver_module = THIS_MODULE,
.attrs = &adis16136_attribute_group,
.read_raw = &adis16136_read_raw,
.write_raw = &adis16136_write_raw,
.update_scan_mode = adis_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
static int adis16136_stop_device(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
int ret;
ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff);
if (ret)
dev_err(&indio_dev->dev,
"Could not power down device: %d\n", ret);
return ret;
}
static int adis16136_initial_setup(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int device_id;
uint16_t prod_id;
int ret;
ret = adis_initial_startup(&adis16136->adis);
if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
if (ret)
return ret;
sscanf(indio_dev->name, "adis%u\n", &device_id);
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
device_id, prod_id);
return 0;
}
static const char * const adis16136_status_error_msgs[] = {
[ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed",
[ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure",
[ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error",
[ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
};
static const struct adis_data adis16136_data = {
.diag_stat_reg = ADIS16136_REG_DIAG_STAT,
.glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
.msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
.self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
.startup_delay = 80,
.read_delay = 10,
.write_delay = 10,
.status_error_msgs = adis16136_status_error_msgs,
.status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
};
enum adis16136_id {
ID_ADIS16133,
ID_ADIS16135,
ID_ADIS16136,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
[ID_ADIS16133] = {
.precision = IIO_DEGREE_TO_RAD(1200),
.fullscale = 24000,
},
[ID_ADIS16135] = {
.precision = IIO_DEGREE_TO_RAD(300),
.fullscale = 24000,
},
[ID_ADIS16136] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
},
};
static int adis16136_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct adis16136 *adis16136;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
if (indio_dev == NULL)
return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
adis16136 = iio_priv(indio_dev);
adis16136->chip_info = &adis16136_chip_info[id->driver_data];
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = adis16136_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
indio_dev->info = &adis16136_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
if (ret)
return ret;
ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
if (ret)
return ret;
ret = adis16136_initial_setup(indio_dev);
if (ret)
goto error_cleanup_buffer;
ret = iio_device_register(indio_dev);
if (ret)
goto error_stop_device;
adis16136_debugfs_init(indio_dev);
return 0;
error_stop_device:
adis16136_stop_device(indio_dev);
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
return ret;
}
static int adis16136_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16136 *adis16136 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16136_stop_device(indio_dev);
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
return 0;
}
static const struct spi_device_id adis16136_ids[] = {
{ "adis16133", ID_ADIS16133 },
{ "adis16135", ID_ADIS16135 },
{ "adis16136", ID_ADIS16136 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);
static struct spi_driver adis16136_driver = {
.driver = {
.name = "adis16136",
.owner = THIS_MODULE,
},
.id_table = adis16136_ids,
.probe = adis16136_probe,
.remove = adis16136_remove,
};
module_spi_driver(adis16136_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,389 @@
/*
* ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS16260_STARTUP_DELAY 220 /* ms */
#define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */
#define ADIS16260_AUX_ADC 0x0A /* analog input channel measurement */
#define ADIS16260_TEMP_OUT 0x0C /* internal temperature measurement */
#define ADIS16260_ANGL_OUT 0x0E /* angle displacement */
#define ADIS16260_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */
#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
#define ADIS16260_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */
#define ADIS16260_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */
#define ADIS16260_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */
#define ADIS16260_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */
#define ADIS16260_ALM_CTRL 0x28 /* Alarm control */
#define ADIS16260_AUX_DAC 0x30 /* Auxiliary DAC data */
#define ADIS16260_GPIO_CTRL 0x32 /* Control, digital I/O line */
#define ADIS16260_MSC_CTRL 0x34 /* Control, data ready, self-test settings */
#define ADIS16260_SMPL_PRD 0x36 /* Control, internal sample rate */
#define ADIS16260_SENS_AVG 0x38 /* Control, dynamic range, filtering */
#define ADIS16260_SLP_CNT 0x3A /* Control, sleep mode initiation */
#define ADIS16260_DIAG_STAT 0x3C /* Diagnostic, error flags */
#define ADIS16260_GLOB_CMD 0x3E /* Control, global commands */
#define ADIS16260_LOT_ID1 0x52 /* Lot Identification Code 1 */
#define ADIS16260_LOT_ID2 0x54 /* Lot Identification Code 2 */
#define ADIS16260_PROD_ID 0x56 /* Product identifier;
* convert to decimal = 16,265/16,260 */
#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
#define ADIS16260_ERROR_ACTIVE (1<<14)
#define ADIS16260_NEW_DATA (1<<15)
/* MSC_CTRL */
#define ADIS16260_MSC_CTRL_MEM_TEST (1<<11)
/* Internal self-test enable */
#define ADIS16260_MSC_CTRL_INT_SELF_TEST (1<<10)
#define ADIS16260_MSC_CTRL_NEG_SELF_TEST (1<<9)
#define ADIS16260_MSC_CTRL_POS_SELF_TEST (1<<8)
#define ADIS16260_MSC_CTRL_DATA_RDY_EN (1<<2)
#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
/* SMPL_PRD */
/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
#define ADIS16260_SMPL_PRD_TIME_BASE (1<<7)
#define ADIS16260_SMPL_PRD_DIV_MASK 0x7F
/* SLP_CNT */
#define ADIS16260_SLP_CNT_POWER_OFF 0x80
/* DIAG_STAT */
#define ADIS16260_DIAG_STAT_ALARM2 (1<<9)
#define ADIS16260_DIAG_STAT_ALARM1 (1<<8)
#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6
#define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5
#define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4
#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3
#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2
#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1
#define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16260_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16260_GLOB_CMD_FLASH_UPD (1<<3)
#define ADIS16260_GLOB_CMD_DAC_LATCH (1<<2)
#define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1)
#define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0)
#define ADIS16260_SPI_SLOW (u32)(300 * 1000)
#define ADIS16260_SPI_BURST (u32)(1000 * 1000)
#define ADIS16260_SPI_FAST (u32)(2000 * 1000)
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
#define ADIS16260_SCAN_GYRO 0
#define ADIS16260_SCAN_SUPPLY 1
#define ADIS16260_SCAN_AUX_ADC 2
#define ADIS16260_SCAN_TEMP 3
#define ADIS16260_SCAN_ANGL 4
/* Power down the device */
static int adis16260_stop_device(struct iio_dev *indio_dev)
{
struct adis *adis = iio_priv(indio_dev);
int ret;
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
if (ret)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
return ret;
}
static const struct iio_chan_spec adis16260_channels[] = {
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_CALIBSCALE),
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
IIO_CHAN_SOFT_TIMESTAMP(5),
};
static const u8 adis16260_addresses[][2] = {
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
};
static int adis16260_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct adis *adis = iio_priv(indio_dev);
int ret;
u8 addr;
s16 val16;
switch (mask) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan,
ADIS16260_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
if (spi_get_device_id(adis->spi)->driver_data) {
/* 0.01832 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(18320);
} else {
/* 0.07326 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(73260);
}
return IIO_VAL_INT_PLUS_MICRO;
case IIO_INCLI:
*val = 0;
*val2 = IIO_DEGREE_TO_RAD(36630);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_VOLTAGE:
if (chan->channel == 0) {
*val = 1;
*val2 = 831500; /* 1.8315 mV */
} else {
*val = 0;
*val2 = 610500; /* 610.5 uV */
}
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
*val = 145;
*val2 = 300000; /* 0.1453 C */
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 250000 / 1453; /* 25 C = 0x00 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
addr = adis16260_addresses[chan->scan_index][0];
ret = adis_read_reg_16(adis, addr, &val16);
if (ret)
return ret;
*val = sign_extend32(val16, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
addr = adis16260_addresses[chan->scan_index][1];
ret = adis_read_reg_16(adis, addr, &val16);
if (ret)
return ret;
*val = val16;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &val16);
if (ret)
return ret;
if (spi_get_device_id(adis->spi)->driver_data)
/* If an adis16251 */
*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?
8 : 256;
else
*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?
66 : 2048;
*val /= (val16 & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int adis16260_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct adis *adis = iio_priv(indio_dev);
int ret;
u8 addr;
u8 t;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -2048 || val >= 2048)
return -EINVAL;
addr = adis16260_addresses[chan->scan_index][0];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_CALIBSCALE:
if (val < 0 || val >= 4096)
return -EINVAL;
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&indio_dev->mlock);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
t = 2048 / val;
if (t > ADIS16260_SMPL_PRD_DIV_MASK)
t = ADIS16260_SMPL_PRD_DIV_MASK;
else if (t > 0)
t--;
if (t >= 0x0A)
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
mutex_unlock(&indio_dev->mlock);
return ret;
}
return -EINVAL;
}
static const struct iio_info adis16260_info = {
.read_raw = &adis16260_read_raw,
.write_raw = &adis16260_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE,
};
static const char * const adis1620_status_error_msgs[] = {
[ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error",
[ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error",
[ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange",
[ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25",
[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",
};
static const struct adis_data adis16260_data = {
.write_delay = 30,
.read_delay = 30,
.msc_ctrl_reg = ADIS16260_MSC_CTRL,
.glob_cmd_reg = ADIS16260_GLOB_CMD,
.diag_stat_reg = ADIS16260_DIAG_STAT,
.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
.startup_delay = ADIS16260_STARTUP_DELAY,
.status_error_msgs = adis1620_status_error_msgs,
.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |
BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) |
BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) |
BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT),
};
static int adis16260_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adis *adis;
int ret;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
if (!indio_dev)
return -ENOMEM;
adis = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info;
indio_dev->channels = adis16260_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(adis, indio_dev, spi, &adis16260_data);
if (ret)
return ret;
ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
if (ret)
return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(adis);
if (ret)
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_buffer_trigger;
return 0;
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(adis, indio_dev);
return ret;
}
static int adis16260_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *adis = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev);
adis_cleanup_buffer_and_trigger(adis, indio_dev);
return 0;
}
/*
* These parts do not need to be differentiated until someone adds
* support for the on chip filtering.
*/
static const struct spi_device_id adis16260_id[] = {
{"adis16260", 0},
{"adis16265", 0},
{"adis16250", 0},
{"adis16255", 0},
{"adis16251", 1},
{}
};
MODULE_DEVICE_TABLE(spi, adis16260_id);
static struct spi_driver adis16260_driver = {
.driver = {
.name = "adis16260",
.owner = THIS_MODULE,
},
.probe = adis16260_probe,
.remove = adis16260_remove,
.id_table = adis16260_id,
};
module_spi_driver(adis16260_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor");
MODULE_LICENSE("GPL v2");

468
drivers/iio/gyro/adxrs450.c Normal file
View file

@ -0,0 +1,468 @@
/*
* ADXRS450/ADXRS453 Digital Output Gyroscope Driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define ADXRS450_STARTUP_DELAY 50 /* ms */
/* The MSB for the spi commands */
#define ADXRS450_SENSOR_DATA (0x20 << 24)
#define ADXRS450_WRITE_DATA (0x40 << 24)
#define ADXRS450_READ_DATA (0x80 << 24)
#define ADXRS450_RATE1 0x00 /* Rate Registers */
#define ADXRS450_TEMP1 0x02 /* Temperature Registers */
#define ADXRS450_LOCST1 0x04 /* Low CST Memory Registers */
#define ADXRS450_HICST1 0x06 /* High CST Memory Registers */
#define ADXRS450_QUAD1 0x08 /* Quad Memory Registers */
#define ADXRS450_FAULT1 0x0A /* Fault Registers */
#define ADXRS450_PID1 0x0C /* Part ID Register 1 */
#define ADXRS450_SNH 0x0E /* Serial Number Registers, 4 bytes */
#define ADXRS450_SNL 0x10
#define ADXRS450_DNC1 0x12 /* Dynamic Null Correction Registers */
/* Check bits */
#define ADXRS450_P 0x01
#define ADXRS450_CHK 0x02
#define ADXRS450_CST 0x04
#define ADXRS450_PWR 0x08
#define ADXRS450_POR 0x10
#define ADXRS450_NVM 0x20
#define ADXRS450_Q 0x40
#define ADXRS450_PLL 0x80
#define ADXRS450_UV 0x100
#define ADXRS450_OV 0x200
#define ADXRS450_AMP 0x400
#define ADXRS450_FAIL 0x800
#define ADXRS450_WRERR_MASK (0x7 << 29)
#define ADXRS450_MAX_RX 4
#define ADXRS450_MAX_TX 4
#define ADXRS450_GET_ST(a) ((a >> 26) & 0x3)
enum {
ID_ADXRS450,
ID_ADXRS453,
};
/**
* struct adxrs450_state - device instance specific data
* @us: actual spi_device
* @buf_lock: mutex to protect tx and rx
* @tx: transmit buffer
* @rx: receive buffer
**/
struct adxrs450_state {
struct spi_device *us;
struct mutex buf_lock;
__be32 tx ____cacheline_aligned;
__be32 rx;
};
/**
* adxrs450_spi_read_reg_16() - read 2 bytes from a register pair
* @indio_dev: device associated with child of actual iio_dev
* @reg_address: the address of the lower of the two registers, which should be
* an even address, the second register's address is reg_address + 1.
* @val: somewhere to pass back the value read
**/
static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev,
u8 reg_address,
u16 *val)
{
struct adxrs450_state *st = iio_priv(indio_dev);
u32 tx;
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = &st->tx,
.bits_per_word = 8,
.len = sizeof(st->tx),
.cs_change = 1,
}, {
.rx_buf = &st->rx,
.bits_per_word = 8,
.len = sizeof(st->rx),
},
};
mutex_lock(&st->buf_lock);
tx = ADXRS450_READ_DATA | (reg_address << 17);
if (!(hweight32(tx) & 1))
tx |= ADXRS450_P;
st->tx = cpu_to_be32(tx);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n",
reg_address);
goto error_ret;
}
*val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF;
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair
* @indio_dev: device associated with child of actual actual iio_dev
* @reg_address: the address of the lower of the two registers,which should be
* an even address, the second register's address is reg_address + 1.
* @val: value to be written.
**/
static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev,
u8 reg_address,
u16 val)
{
struct adxrs450_state *st = iio_priv(indio_dev);
u32 tx;
int ret;
mutex_lock(&st->buf_lock);
tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1);
if (!(hweight32(tx) & 1))
tx |= ADXRS450_P;
st->tx = cpu_to_be32(tx);
ret = spi_write(st->us, &st->tx, sizeof(st->tx));
if (ret)
dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n",
reg_address);
usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adxrs450_spi_sensor_data() - read 2 bytes sensor data
* @indio_dev: device associated with child of actual iio_dev
* @val: somewhere to pass back the value read
**/
static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val)
{
struct adxrs450_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = &st->tx,
.bits_per_word = 8,
.len = sizeof(st->tx),
.cs_change = 1,
}, {
.rx_buf = &st->rx,
.bits_per_word = 8,
.len = sizeof(st->rx),
},
};
mutex_lock(&st->buf_lock);
st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->us->dev, "Problem while reading sensor data\n");
goto error_ret;
}
*val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF;
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adxrs450_spi_initial() - use for initializing procedure.
* @st: device instance specific data
* @val: somewhere to pass back the value read
* @chk: Whether to perform fault check
**/
static int adxrs450_spi_initial(struct adxrs450_state *st,
u32 *val, char chk)
{
int ret;
u32 tx;
struct spi_transfer xfers = {
.tx_buf = &st->tx,
.rx_buf = &st->rx,
.bits_per_word = 8,
.len = sizeof(st->tx),
};
mutex_lock(&st->buf_lock);
tx = ADXRS450_SENSOR_DATA;
if (chk)
tx |= (ADXRS450_CHK | ADXRS450_P);
st->tx = cpu_to_be32(tx);
ret = spi_sync_transfer(st->us, &xfers, 1);
if (ret) {
dev_err(&st->us->dev, "Problem while reading initializing data\n");
goto error_ret;
}
*val = be32_to_cpu(st->rx);
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
/* Recommended Startup Sequence by spec */
static int adxrs450_initial_setup(struct iio_dev *indio_dev)
{
u32 t;
u16 data;
int ret;
struct adxrs450_state *st = iio_priv(indio_dev);
msleep(ADXRS450_STARTUP_DELAY*2);
ret = adxrs450_spi_initial(st, &t, 1);
if (ret)
return ret;
if (t != 0x01)
dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n");
msleep(ADXRS450_STARTUP_DELAY);
ret = adxrs450_spi_initial(st, &t, 0);
if (ret)
return ret;
msleep(ADXRS450_STARTUP_DELAY);
ret = adxrs450_spi_initial(st, &t, 0);
if (ret)
return ret;
if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
dev_err(&st->us->dev, "The second response is not correct!\n");
return -EIO;
}
ret = adxrs450_spi_initial(st, &t, 0);
if (ret)
return ret;
if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
dev_err(&st->us->dev, "The third response is not correct!\n");
return -EIO;
}
ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data);
if (ret)
return ret;
if (data & 0x0fff) {
dev_err(&st->us->dev, "The device is not in normal status!\n");
return -EINVAL;
}
return 0;
}
static int adxrs450_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -0x400 || val >= 0x400)
return -EINVAL;
ret = adxrs450_spi_write_reg_16(indio_dev,
ADXRS450_DNC1, val);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int adxrs450_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
int ret;
s16 t;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_ANGL_VEL:
ret = adxrs450_spi_sensor_data(indio_dev, &t);
if (ret)
break;
*val = t;
ret = IIO_VAL_INT;
break;
case IIO_TEMP:
ret = adxrs450_spi_read_reg_16(indio_dev,
ADXRS450_TEMP1, &t);
if (ret)
break;
*val = (t >> 6) + 225;
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
*val2 = 218166;
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
*val = 200;
*val2 = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW:
ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t);
if (ret)
break;
*val = t;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_CALIBBIAS:
ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t);
if (ret)
break;
*val = sign_extend32(t, 9);
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct iio_chan_spec adxrs450_channels[2][2] = {
[ID_ADXRS450] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}
},
[ID_ADXRS453] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW),
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
}
},
};
static const struct iio_info adxrs450_info = {
.driver_module = THIS_MODULE,
.read_raw = &adxrs450_read_raw,
.write_raw = &adxrs450_write_raw,
};
static int adxrs450_probe(struct spi_device *spi)
{
int ret;
struct adxrs450_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
/* This is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adxrs450_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels =
adxrs450_channels[spi_get_device_id(spi)->driver_data];
indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels);
indio_dev->name = spi->dev.driver->name;
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return ret;
/* Get the device into a sane initial state */
ret = adxrs450_initial_setup(indio_dev);
if (ret)
return ret;
return 0;
}
static const struct spi_device_id adxrs450_id[] = {
{"adxrs450", ID_ADXRS450},
{"adxrs453", ID_ADXRS453},
{}
};
MODULE_DEVICE_TABLE(spi, adxrs450_id);
static struct spi_driver adxrs450_driver = {
.driver = {
.name = "adxrs450",
.owner = THIS_MODULE,
},
.probe = adxrs450_probe,
.id_table = adxrs450_id,
};
module_spi_driver(adxrs450_driver);
MODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>");
MODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver");
MODULE_LICENSE("GPL v2");

1273
drivers/iio/gyro/bmg160.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,427 @@
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum gyro_3d_channel {
CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y,
CHANNEL_SCAN_INDEX_Z,
GYRO_3D_CHANNEL_MAX,
};
struct gyro_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];
u32 gyro_val[GYRO_3D_CHANNEL_MAX];
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
};
static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS,
HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS,
HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS
};
/* Channel definitions */
static const struct iio_chan_spec gyro_3d_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
/* Adjust channel real bits based on report descriptor */
static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
channels[channel].scan_type.realbits = size * 8;
/* Maximum size of a sample to capture is u32 */
channels[channel].scan_type.storagebits = sizeof(u32) * 8;
}
/* Channel read_raw handler */
static int gyro_3d_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int report_id = -1;
u32 address;
int ret_type;
s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case 0:
poll_value = hid_sensor_read_poll_value(
&gyro_state->common_attributes);
if (poll_value < 0)
return -EINVAL;
hid_sensor_power_state(&gyro_state->common_attributes, true);
msleep_interruptible(poll_value * 2);
report_id = gyro_state->gyro[chan->scan_index].report_id;
address = gyro_3d_addresses[chan->scan_index];
if (report_id >= 0)
*val = sensor_hub_input_attr_get_raw_value(
gyro_state->common_attributes.hsdev,
HID_USAGE_SENSOR_GYRO_3D, address,
report_id);
else {
*val = 0;
hid_sensor_power_state(&gyro_state->common_attributes,
false);
return -EINVAL;
}
hid_sensor_power_state(&gyro_state->common_attributes, false);
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = gyro_state->scale_pre_decml;
*val2 = gyro_state->scale_post_decml;
ret_type = gyro_state->scale_precision;
break;
case IIO_CHAN_INFO_OFFSET:
*val = gyro_state->value_offset;
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SAMP_FREQ:
ret_type = hid_sensor_read_samp_freq_value(
&gyro_state->common_attributes, val, val2);
break;
case IIO_CHAN_INFO_HYSTERESIS:
ret_type = hid_sensor_read_raw_hyst_value(
&gyro_state->common_attributes, val, val2);
break;
default:
ret_type = -EINVAL;
break;
}
return ret_type;
}
/* Channel write_raw handler */
static int gyro_3d_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int ret = 0;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
ret = hid_sensor_write_samp_freq_value(
&gyro_state->common_attributes, val, val2);
break;
case IIO_CHAN_INFO_HYSTERESIS:
ret = hid_sensor_write_raw_hyst_value(
&gyro_state->common_attributes, val, val2);
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct iio_info gyro_3d_info = {
.driver_module = THIS_MODULE,
.read_raw = &gyro_3d_read_raw,
.write_raw = &gyro_3d_write_raw,
};
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
int len)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, data);
}
/* Callback handler to send event after all samples are received and captured */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");
if (atomic_read(&gyro_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
gyro_state->gyro_val,
sizeof(gyro_state->gyro_val));
return 0;
}
/* Capture samples in local storage */
static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
size_t raw_len, char *raw_data,
void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int offset;
int ret = -EINVAL;
switch (usage_id) {
case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS:
case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS:
case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;
gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
ret = 0;
break;
default:
break;
}
return ret;
}
/* Parse report which is specific to an usage id*/
static int gyro_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
unsigned usage_id,
struct gyro_3d_state *st)
{
int ret;
int i;
for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i,
&st->gyro[CHANNEL_SCAN_INDEX_X + i]);
if (ret < 0)
break;
gyro_3d_adjust_channel_bit_mask(channels,
CHANNEL_SCAN_INDEX_X + i,
st->gyro[CHANNEL_SCAN_INDEX_X + i].size);
}
dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
st->gyro[0].index,
st->gyro[0].report_id,
st->gyro[1].index, st->gyro[1].report_id,
st->gyro[2].index, st->gyro[2].report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_GYRO_3D,
&st->gyro[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
/* Set Sensitivity field ids, when there is no individual modifier */
if (st->common_attributes.sensitivity.index < 0) {
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,
&st->common_attributes.sensitivity);
dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
st->common_attributes.sensitivity.index,
st->common_attributes.sensitivity.report_id);
}
return ret;
}
/* Function to initialize the processing for usage id */
static int hid_gyro_3d_probe(struct platform_device *pdev)
{
int ret = 0;
static const char *name = "gyro_3d";
struct iio_dev *indio_dev;
struct gyro_3d_state *gyro_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
gyro_state = iio_priv(indio_dev);
gyro_state->common_attributes.hsdev = hsdev;
gyro_state->common_attributes.pdev = pdev;
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_GYRO_3D,
&gyro_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
GFP_KERNEL);
if (!channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = gyro_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_GYRO_3D, gyro_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &gyro_3d_info;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem;
}
atomic_set(&gyro_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
&gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
goto error_unreg_buffer_funcs;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "device register failed\n");
goto error_remove_trigger;
}
gyro_state->callbacks.send_event = gyro_3d_proc_event;
gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;
gyro_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
&gyro_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
goto error_iio_unreg;
}
return ret;
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(&gyro_state->common_attributes);
error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret;
}
/* Function to deinitialize the processing for usage id */
static int hid_gyro_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&gyro_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
return 0;
}
static struct platform_device_id hid_gyro_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200076",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);
static struct platform_driver hid_gyro_3d_platform_driver = {
.id_table = hid_gyro_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
},
.probe = hid_gyro_3d_probe,
.remove = hid_gyro_3d_remove,
};
module_platform_driver(hid_gyro_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Gyroscope 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,153 @@
/*
* itg3200_buffer.c -- support InvenSense ITG3200
* Digital 3-Axis Gyroscope driver
*
* Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de>
* Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/gyro/itg3200.h>
static int itg3200_read_all_channels(struct i2c_client *i2c, __be16 *buf)
{
u8 tx = 0x80 | ITG3200_REG_TEMP_OUT_H;
struct i2c_msg msg[2] = {
{
.addr = i2c->addr,
.flags = i2c->flags,
.len = 1,
.buf = &tx,
},
{
.addr = i2c->addr,
.flags = i2c->flags | I2C_M_RD,
.len = ITG3200_SCAN_ELEMENTS * sizeof(s16),
.buf = (char *)&buf,
},
};
return i2c_transfer(i2c->adapter, msg, 2);
}
static irqreturn_t itg3200_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct itg3200 *st = iio_priv(indio_dev);
__be16 buf[ITG3200_SCAN_ELEMENTS + sizeof(s64)/sizeof(u16)];
int ret = itg3200_read_all_channels(st->i2c, buf);
if (ret < 0)
goto error_ret;
iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
error_ret:
return IRQ_HANDLED;
}
int itg3200_buffer_configure(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
itg3200_trigger_handler, NULL);
}
void itg3200_buffer_unconfigure(struct iio_dev *indio_dev)
{
iio_triggered_buffer_cleanup(indio_dev);
}
static int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
int ret;
u8 msc;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, &msc);
if (ret)
goto error_ret;
if (state)
msc |= ITG3200_IRQ_DATA_RDY_ENABLE;
else
msc &= ~ITG3200_IRQ_DATA_RDY_ENABLE;
ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, msc);
if (ret)
goto error_ret;
error_ret:
return ret;
}
static const struct iio_trigger_ops itg3200_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &itg3200_data_rdy_trigger_set_state,
};
int itg3200_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct itg3200 *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
indio_dev->id);
if (!st->trig)
return -ENOMEM;
ret = request_irq(st->i2c->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"itg3200_data_rdy",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->i2c->dev;
st->trig->ops = &itg3200_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
if (ret)
goto error_free_irq;
/* select default trigger */
indio_dev->trig = iio_trigger_get(st->trig);
return 0;
error_free_irq:
free_irq(st->i2c->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
return ret;
}
void itg3200_remove_trigger(struct iio_dev *indio_dev)
{
struct itg3200 *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->i2c->irq, st->trig);
iio_trigger_free(st->trig);
}

View file

@ -0,0 +1,374 @@
/*
* itg3200_core.c -- support InvenSense ITG3200
* Digital 3-Axis Gyroscope driver
*
* Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de>
* Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de>
*
* 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.
*
* TODO:
* - Support digital low pass filter
* - Support power management
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
#include <linux/iio/gyro/itg3200.h>
int itg3200_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address, u8 val)
{
struct itg3200 *st = iio_priv(indio_dev);
return i2c_smbus_write_byte_data(st->i2c, 0x80 | reg_address, val);
}
int itg3200_read_reg_8(struct iio_dev *indio_dev,
u8 reg_address, u8 *val)
{
struct itg3200 *st = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_read_byte_data(st->i2c, reg_address);
if (ret < 0)
return ret;
*val = ret;
return 0;
}
static int itg3200_read_reg_s16(struct iio_dev *indio_dev, u8 lower_reg_address,
int *val)
{
struct itg3200 *st = iio_priv(indio_dev);
struct i2c_client *client = st->i2c;
int ret;
s16 out;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = client->flags,
.len = 1,
.buf = (char *)&lower_reg_address,
},
{
.addr = client->addr,
.flags = client->flags | I2C_M_RD,
.len = 2,
.buf = (char *)&out,
},
};
lower_reg_address |= 0x80;
ret = i2c_transfer(client->adapter, msg, 2);
be16_to_cpus(&out);
*val = out;
return (ret == 2) ? 0 : ret;
}
static int itg3200_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long info)
{
int ret = 0;
u8 reg;
u8 regval;
switch (info) {
case IIO_CHAN_INFO_RAW:
reg = (u8)chan->address;
ret = itg3200_read_reg_s16(indio_dev, reg, val);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
if (chan->type == IIO_TEMP)
*val2 = 1000000000/280;
else
*val2 = 1214142; /* (1 / 14,375) * (PI / 180) */
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_OFFSET:
/* Only the temperature channel has an offset */
*val = 23000;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &regval);
if (ret)
return ret;
*val = (regval & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
ret = itg3200_read_reg_8(indio_dev,
ITG3200_REG_SAMPLE_RATE_DIV,
&regval);
if (ret)
return ret;
*val /= regval + 1;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int itg3200_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
int ret;
u8 t;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (val == 0 || val2 != 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
ret = itg3200_write_reg_8(indio_dev,
ITG3200_REG_SAMPLE_RATE_DIV,
t);
mutex_unlock(&indio_dev->mlock);
return ret;
default:
return -EINVAL;
}
}
/*
* Reset device and internal registers to the power-up-default settings
* Use the gyro clock as reference, as suggested by the datasheet
*/
static int itg3200_reset(struct iio_dev *indio_dev)
{
struct itg3200 *st = iio_priv(indio_dev);
int ret;
dev_dbg(&st->i2c->dev, "reset device");
ret = itg3200_write_reg_8(indio_dev,
ITG3200_REG_POWER_MANAGEMENT,
ITG3200_RESET);
if (ret) {
dev_err(&st->i2c->dev, "error resetting device");
goto error_ret;
}
/* Wait for PLL (1ms according to datasheet) */
udelay(1500);
ret = itg3200_write_reg_8(indio_dev,
ITG3200_REG_IRQ_CONFIG,
ITG3200_IRQ_ACTIVE_HIGH |
ITG3200_IRQ_PUSH_PULL |
ITG3200_IRQ_LATCH_50US_PULSE |
ITG3200_IRQ_LATCH_CLEAR_ANY);
if (ret)
dev_err(&st->i2c->dev, "error init device");
error_ret:
return ret;
}
/* itg3200_enable_full_scale() - Disables the digital low pass filter */
static int itg3200_enable_full_scale(struct iio_dev *indio_dev)
{
u8 val;
int ret;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val);
if (ret)
goto err_ret;
val |= ITG3200_DLPF_FS_SEL_2000;
return itg3200_write_reg_8(indio_dev, ITG3200_REG_DLPF, val);
err_ret:
return ret;
}
static int itg3200_initial_setup(struct iio_dev *indio_dev)
{
struct itg3200 *st = iio_priv(indio_dev);
int ret;
u8 val;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_ADDRESS, &val);
if (ret)
goto err_ret;
if (((val >> 1) & 0x3f) != 0x34) {
dev_err(&st->i2c->dev, "invalid reg value 0x%02x", val);
ret = -ENXIO;
goto err_ret;
}
ret = itg3200_reset(indio_dev);
if (ret)
goto err_ret;
ret = itg3200_enable_full_scale(indio_dev);
err_ret:
return ret;
}
#define ITG3200_ST \
{ .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
#define ITG3200_GYRO_CHAN(_mod) { \
.type = IIO_ANGL_VEL, \
.modified = 1, \
.channel2 = IIO_MOD_ ## _mod, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
.scan_type = ITG3200_ST, \
}
static const struct iio_chan_spec itg3200_channels[] = {
{
.type = IIO_TEMP,
.channel2 = IIO_NO_MOD,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.address = ITG3200_REG_TEMP_OUT_H,
.scan_index = ITG3200_SCAN_TEMP,
.scan_type = ITG3200_ST,
},
ITG3200_GYRO_CHAN(X),
ITG3200_GYRO_CHAN(Y),
ITG3200_GYRO_CHAN(Z),
IIO_CHAN_SOFT_TIMESTAMP(ITG3200_SCAN_ELEMENTS),
};
static const struct iio_info itg3200_info = {
.read_raw = &itg3200_read_raw,
.write_raw = &itg3200_write_raw,
.driver_module = THIS_MODULE,
};
static const unsigned long itg3200_available_scan_masks[] = { 0xffffffff, 0x0 };
static int itg3200_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct itg3200 *st;
struct iio_dev *indio_dev;
dev_dbg(&client->dev, "probe I2C dev with IRQ %i", client->irq);
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
st->i2c = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = client->dev.driver->name;
indio_dev->channels = itg3200_channels;
indio_dev->num_channels = ARRAY_SIZE(itg3200_channels);
indio_dev->available_scan_masks = itg3200_available_scan_masks;
indio_dev->info = &itg3200_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = itg3200_buffer_configure(indio_dev);
if (ret)
return ret;
if (client->irq) {
ret = itg3200_probe_trigger(indio_dev);
if (ret)
goto error_unconfigure_buffer;
}
ret = itg3200_initial_setup(indio_dev);
if (ret)
goto error_remove_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
if (client->irq)
itg3200_remove_trigger(indio_dev);
error_unconfigure_buffer:
itg3200_buffer_unconfigure(indio_dev);
return ret;
}
static int itg3200_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
if (client->irq)
itg3200_remove_trigger(indio_dev);
itg3200_buffer_unconfigure(indio_dev);
return 0;
}
static const struct i2c_device_id itg3200_id[] = {
{ "itg3200", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, itg3200_id);
static struct i2c_driver itg3200_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "itg3200",
},
.id_table = itg3200_id,
.probe = itg3200_probe,
.remove = itg3200_remove,
};
module_i2c_driver(itg3200_driver);
MODULE_AUTHOR("Christian Strobel <christian.strobel@iis.fraunhofer.de>");
MODULE_DESCRIPTION("ITG3200 Gyroscope I2C driver");
MODULE_LICENSE("GPL v2");

Some files were not shown because too many files have changed in this diff Show more