574fb258d6
Example of how a device with a hardware ring buffer is handled within IIO. Changes since V2: * Moved to new registration functions giving much cleaner interface. Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
1510 lines
38 KiB
C
1510 lines
38 KiB
C
/*
|
|
* sca3000_core.c -- support VTI sca3000 series accelerometers via SPI
|
|
*
|
|
* 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.
|
|
*
|
|
* Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk>
|
|
*
|
|
* See industrialio/accels/sca3000.h for comments.
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/sysfs.h>
|
|
#include "../iio.h"
|
|
#include "../sysfs.h"
|
|
#include "../ring_generic.h"
|
|
|
|
#include "accel.h"
|
|
#include "sca3000.h"
|
|
|
|
enum sca3000_variant {
|
|
d01,
|
|
d03,
|
|
e02,
|
|
e04,
|
|
e05,
|
|
l01,
|
|
};
|
|
|
|
/* Note where option modes are not defined, the chip simply does not
|
|
* support any.
|
|
* Other chips in the sca3000 series use i2c and are not included here.
|
|
*
|
|
* Some of these devices are only listed in the family data sheet and
|
|
* do not actually appear to be available.
|
|
*/
|
|
static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = {
|
|
{
|
|
.name = "sca3000-d01",
|
|
.temp_output = true,
|
|
.measurement_mode_freq = 250,
|
|
.option_mode_1 = SCA3000_OP_MODE_BYPASS,
|
|
.option_mode_1_freq = 250,
|
|
}, {
|
|
/* No data sheet available - may be the same as the 3100-d03?*/
|
|
.name = "sca3000-d03",
|
|
.temp_output = true,
|
|
}, {
|
|
.name = "sca3000-e02",
|
|
.measurement_mode_freq = 125,
|
|
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
|
.option_mode_1_freq = 63,
|
|
}, {
|
|
.name = "sca3000-e04",
|
|
.measurement_mode_freq = 100,
|
|
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
|
.option_mode_1_freq = 50,
|
|
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
|
.option_mode_2_freq = 400,
|
|
}, {
|
|
.name = "sca3000-e05",
|
|
.measurement_mode_freq = 200,
|
|
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
|
.option_mode_1_freq = 50,
|
|
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
|
.option_mode_2_freq = 400,
|
|
}, {
|
|
/* No data sheet available.
|
|
* Frequencies are unknown.
|
|
*/
|
|
.name = "sca3000-l01",
|
|
.temp_output = true,
|
|
.option_mode_1 = SCA3000_OP_MODE_BYPASS,
|
|
},
|
|
};
|
|
|
|
|
|
int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val)
|
|
{
|
|
struct spi_transfer xfer = {
|
|
.bits_per_word = 8,
|
|
.len = 2,
|
|
.cs_change = 1,
|
|
.tx_buf = st->tx,
|
|
};
|
|
struct spi_message msg;
|
|
|
|
st->tx[0] = SCA3000_WRITE_REG(address);
|
|
st->tx[1] = val;
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer, &msg);
|
|
|
|
return spi_sync(st->us, &msg);
|
|
}
|
|
|
|
int sca3000_read_data(struct sca3000_state *st,
|
|
uint8_t reg_address_high,
|
|
u8 **rx_p,
|
|
int len)
|
|
{
|
|
int ret;
|
|
struct spi_message msg;
|
|
struct spi_transfer xfer = {
|
|
.bits_per_word = 8,
|
|
.len = len + 1,
|
|
.cs_change = 1,
|
|
.tx_buf = st->tx,
|
|
};
|
|
|
|
*rx_p = kmalloc(len + 1, GFP_KERNEL);
|
|
if (*rx_p == NULL) {
|
|
ret = -ENOMEM;
|
|
goto error_ret;
|
|
}
|
|
xfer.rx_buf = *rx_p;
|
|
st->tx[0] = SCA3000_READ_REG(reg_address_high);
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer, &msg);
|
|
|
|
ret = spi_sync(st->us, &msg);
|
|
|
|
if (ret) {
|
|
dev_err(get_device(&st->us->dev), "problem reading register");
|
|
goto error_free_rx;
|
|
}
|
|
|
|
return 0;
|
|
error_free_rx:
|
|
kfree(*rx_p);
|
|
error_ret:
|
|
return ret;
|
|
|
|
}
|
|
/**
|
|
* sca3000_reg_lock_on() test if the ctrl register lock is on
|
|
*
|
|
* Lock must be held.
|
|
**/
|
|
static int sca3000_reg_lock_on(struct sca3000_state *st)
|
|
{
|
|
u8 *rx;
|
|
int ret;
|
|
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_STATUS, &rx, 1);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
ret = !(rx[1] & SCA3000_LOCKED);
|
|
kfree(rx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* __sca3000_unlock_reg_lock() unlock the control registers
|
|
*
|
|
* Note the device does not appear to support doing this in a single transfer.
|
|
* This should only ever be used as part of ctrl reg read.
|
|
* Lock must be held before calling this
|
|
**/
|
|
static int __sca3000_unlock_reg_lock(struct sca3000_state *st)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer xfer[3] = {
|
|
{
|
|
.bits_per_word = 8,
|
|
.len = 2,
|
|
.cs_change = 1,
|
|
.tx_buf = st->tx,
|
|
}, {
|
|
.bits_per_word = 8,
|
|
.len = 2,
|
|
.cs_change = 1,
|
|
.tx_buf = st->tx + 2,
|
|
}, {
|
|
.bits_per_word = 8,
|
|
.len = 2,
|
|
.cs_change = 1,
|
|
.tx_buf = st->tx + 4,
|
|
},
|
|
};
|
|
st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK);
|
|
st->tx[1] = 0x00;
|
|
st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK);
|
|
st->tx[3] = 0x50;
|
|
st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK);
|
|
st->tx[5] = 0xA0;
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
spi_message_add_tail(&xfer[1], &msg);
|
|
spi_message_add_tail(&xfer[2], &msg);
|
|
|
|
return spi_sync(st->us, &msg);
|
|
}
|
|
|
|
/**
|
|
* sca3000_write_ctrl_reg() write to a lock protect ctrl register
|
|
* @sel: selects which registers we wish to write to
|
|
* @val: the value to be written
|
|
*
|
|
* Certain control registers are protected against overwriting by the lock
|
|
* register and use a shared write address. This function allows writing of
|
|
* these registers.
|
|
* Lock must be held.
|
|
**/
|
|
static int sca3000_write_ctrl_reg(struct sca3000_state *st,
|
|
uint8_t sel,
|
|
uint8_t val)
|
|
{
|
|
|
|
int ret;
|
|
|
|
ret = sca3000_reg_lock_on(st);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
if (ret) {
|
|
ret = __sca3000_unlock_reg_lock(st);
|
|
if (ret)
|
|
goto error_ret;
|
|
}
|
|
|
|
/* Set the control select register */
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, sel);
|
|
if (ret)
|
|
goto error_ret;
|
|
|
|
/* Write the actual value into the register */
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_DATA, val);
|
|
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
/* Crucial that lock is called before calling this */
|
|
/**
|
|
* sca3000_read_ctrl_reg() read from lock protected control register.
|
|
*
|
|
* Lock must be held.
|
|
**/
|
|
static int sca3000_read_ctrl_reg(struct sca3000_state *st,
|
|
u8 ctrl_reg,
|
|
u8 **rx_p)
|
|
{
|
|
int ret;
|
|
|
|
ret = sca3000_reg_lock_on(st);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
if (ret) {
|
|
ret = __sca3000_unlock_reg_lock(st);
|
|
if (ret)
|
|
goto error_ret;
|
|
}
|
|
/* Set the control select register */
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, ctrl_reg);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_CTRL_DATA, rx_p, 1);
|
|
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
#ifdef SCA3000_DEBUG
|
|
/**
|
|
* sca3000_check_status() check the status register
|
|
*
|
|
* Only used for debugging purposes
|
|
**/
|
|
static int sca3000_check_status(struct device *dev)
|
|
{
|
|
u8 *rx;
|
|
int ret;
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_STATUS, &rx, 1);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
if (rx[1] & SCA3000_EEPROM_CS_ERROR)
|
|
dev_err(dev, "eeprom error \n");
|
|
if (rx[1] & SCA3000_SPI_FRAME_ERROR)
|
|
dev_err(dev, "Previous SPI Frame was corrupt\n");
|
|
kfree(rx);
|
|
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
return ret;
|
|
}
|
|
#endif /* SCA3000_DEBUG */
|
|
|
|
/**
|
|
* sca3000_read_13bit_signed() sysfs interface to read 13 bit signed registers
|
|
*
|
|
* These are described as signed 12 bit on the data sheet, which appears
|
|
* to be a conventional 2's complement 13 bit.
|
|
**/
|
|
static ssize_t sca3000_read_13bit_signed(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int len = 0, ret;
|
|
int val;
|
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
|
u8 *rx;
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, this_attr->address, &rx, 2);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
val = sca3000_13bit_convert(rx[1], rx[2]);
|
|
len += sprintf(buf + len, "%d\n", val);
|
|
kfree(rx);
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
|
|
static ssize_t sca3000_show_name(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
return sprintf(buf, "%s\n", st->info->name);
|
|
}
|
|
/**
|
|
* sca3000_show_reg() - sysfs interface to read the chip revision number
|
|
**/
|
|
static ssize_t sca3000_show_rev(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int len = 0, ret;
|
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_REVID, &rx, 1);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
len += sprintf(buf + len,
|
|
"major=%d, minor=%d\n",
|
|
rx[1] & SCA3000_REVID_MAJOR_MASK,
|
|
rx[1] & SCA3000_REVID_MINOR_MASK);
|
|
kfree(rx);
|
|
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_show_available_measurement_modes() display available modes
|
|
*
|
|
* This is all read from chip specific data in the driver. Not all
|
|
* of the sca3000 series support modes other than normal.
|
|
**/
|
|
static ssize_t
|
|
sca3000_show_available_measurement_modes(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
int len = 0;
|
|
|
|
len += sprintf(buf + len, "0 - normal mode");
|
|
switch (st->info->option_mode_1) {
|
|
case SCA3000_OP_MODE_NARROW:
|
|
len += sprintf(buf + len, ", 1 - narrow mode");
|
|
break;
|
|
case SCA3000_OP_MODE_BYPASS:
|
|
len += sprintf(buf + len, ", 1 - bypass mode");
|
|
break;
|
|
};
|
|
switch (st->info->option_mode_2) {
|
|
case SCA3000_OP_MODE_WIDE:
|
|
len += sprintf(buf + len, ", 2 - wide mode");
|
|
break;
|
|
}
|
|
/* always supported */
|
|
len += sprintf(buf + len, " 3 - motion detection \n");
|
|
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_show_measurmenet_mode() sysfs read of current mode
|
|
**/
|
|
static ssize_t
|
|
sca3000_show_measurement_mode(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
int len = 0, ret;
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
/* mask bottom 2 bits - only ones that are relevant */
|
|
rx[1] &= 0x03;
|
|
switch (rx[1]) {
|
|
case SCA3000_MEAS_MODE_NORMAL:
|
|
len += sprintf(buf + len, "0 - normal mode\n");
|
|
break;
|
|
case SCA3000_MEAS_MODE_MOT_DET:
|
|
len += sprintf(buf + len, "3 - motion detection\n");
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_1:
|
|
switch (st->info->option_mode_1) {
|
|
case SCA3000_OP_MODE_NARROW:
|
|
len += sprintf(buf + len, "1 - narrow mode\n");
|
|
break;
|
|
case SCA3000_OP_MODE_BYPASS:
|
|
len += sprintf(buf + len, "1 - bypass mode\n");
|
|
break;
|
|
};
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_2:
|
|
switch (st->info->option_mode_2) {
|
|
case SCA3000_OP_MODE_WIDE:
|
|
len += sprintf(buf + len, "2 - wide mode\n");
|
|
break;
|
|
}
|
|
break;
|
|
};
|
|
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_store_measurement_mode() set the current mode
|
|
**/
|
|
static ssize_t
|
|
sca3000_store_measurement_mode(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *dev_info = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
int ret;
|
|
u8 *rx;
|
|
int mask = 0x03;
|
|
long val;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
rx[1] &= ~mask;
|
|
rx[1] |= (val & mask);
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, rx[1]);
|
|
if (ret)
|
|
goto error_free_rx;
|
|
mutex_unlock(&st->lock);
|
|
|
|
return len;
|
|
|
|
error_free_rx:
|
|
kfree(rx);
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Not even vaguely standard attributes so defined here rather than
|
|
* in the relevant IIO core headers
|
|
*/
|
|
static IIO_DEVICE_ATTR(available_measurement_modes, S_IRUGO,
|
|
sca3000_show_available_measurement_modes,
|
|
NULL, 0);
|
|
|
|
static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR,
|
|
sca3000_show_measurement_mode,
|
|
sca3000_store_measurement_mode,
|
|
0);
|
|
|
|
/* More standard attributes */
|
|
|
|
static IIO_DEV_ATTR_NAME(sca3000_show_name);
|
|
static IIO_DEV_ATTR_REV(sca3000_show_rev);
|
|
|
|
static IIO_DEV_ATTR_ACCEL_X(sca3000_read_13bit_signed,
|
|
SCA3000_REG_ADDR_X_MSB);
|
|
static IIO_DEV_ATTR_ACCEL_Y(sca3000_read_13bit_signed,
|
|
SCA3000_REG_ADDR_Y_MSB);
|
|
static IIO_DEV_ATTR_ACCEL_Z(sca3000_read_13bit_signed,
|
|
SCA3000_REG_ADDR_Z_MSB);
|
|
|
|
|
|
/**
|
|
* sca3000_read_av_freq() sysfs function to get available frequencies
|
|
*
|
|
* The later modes are only relevant to the ring buffer - and depend on current
|
|
* mode. Note that data sheet gives rather wide tolerances for these so integer
|
|
* division will give good enough answer and not all chips have them specified
|
|
* at all.
|
|
**/
|
|
static ssize_t sca3000_read_av_freq(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
int len = 0, ret;
|
|
u8 *rx;
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
goto error_ret;
|
|
rx[1] &= 0x03;
|
|
switch (rx[1]) {
|
|
case SCA3000_MEAS_MODE_NORMAL:
|
|
len += sprintf(buf + len, "%d %d %d\n",
|
|
st->info->measurement_mode_freq,
|
|
st->info->measurement_mode_freq/2,
|
|
st->info->measurement_mode_freq/4);
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_1:
|
|
len += sprintf(buf + len, "%d %d %d\n",
|
|
st->info->option_mode_1_freq,
|
|
st->info->option_mode_1_freq/2,
|
|
st->info->option_mode_1_freq/4);
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_2:
|
|
len += sprintf(buf + len, "%d %d %d\n",
|
|
st->info->option_mode_2_freq,
|
|
st->info->option_mode_2_freq/2,
|
|
st->info->option_mode_2_freq/4);
|
|
break;
|
|
};
|
|
kfree(rx);
|
|
return len;
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
/**
|
|
* __sca3000_get_base_frequency() obtain mode specific base frequency
|
|
*
|
|
* lock must be held
|
|
**/
|
|
static inline int __sca3000_get_base_freq(struct sca3000_state *st,
|
|
const struct sca3000_chip_info *info,
|
|
int *base_freq)
|
|
{
|
|
int ret;
|
|
u8 *rx;
|
|
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
switch (0x03 & rx[1]) {
|
|
case SCA3000_MEAS_MODE_NORMAL:
|
|
*base_freq = info->measurement_mode_freq;
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_1:
|
|
*base_freq = info->option_mode_1_freq;
|
|
break;
|
|
case SCA3000_MEAS_MODE_OP_2:
|
|
*base_freq = info->option_mode_2_freq;
|
|
break;
|
|
};
|
|
kfree(rx);
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* sca3000_read_frequency() sysfs interface to get the current frequency
|
|
**/
|
|
static ssize_t sca3000_read_frequency(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
int ret, len = 0, base_freq = 0;
|
|
u8 *rx;
|
|
mutex_lock(&st->lock);
|
|
ret = __sca3000_get_base_freq(st, st->info, &base_freq);
|
|
if (ret)
|
|
goto error_ret_mut;
|
|
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, &rx);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
goto error_ret;
|
|
if (base_freq > 0)
|
|
switch (rx[1]&0x03) {
|
|
case 0x00:
|
|
case 0x03:
|
|
len = sprintf(buf, "%d\n", base_freq);
|
|
break;
|
|
case 0x01:
|
|
len = sprintf(buf, "%d\n", base_freq/2);
|
|
break;
|
|
case 0x02:
|
|
len = sprintf(buf, "%d\n", base_freq/4);
|
|
break;
|
|
};
|
|
kfree(rx);
|
|
return len;
|
|
error_ret_mut:
|
|
mutex_unlock(&st->lock);
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* sca3000_set_frequency() sysfs interface to set the current frequency
|
|
**/
|
|
static ssize_t sca3000_set_frequency(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
int ret, base_freq = 0;
|
|
u8 *rx;
|
|
long val;
|
|
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
mutex_lock(&st->lock);
|
|
/* What mode are we in? */
|
|
ret = __sca3000_get_base_freq(st, st->info, &base_freq);
|
|
if (ret)
|
|
goto error_free_lock;
|
|
|
|
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, &rx);
|
|
if (ret)
|
|
goto error_free_lock;
|
|
/* clear the bits */
|
|
rx[1] &= ~0x03;
|
|
|
|
if (val == base_freq/2) {
|
|
rx[1] |= SCA3000_OUT_CTRL_BUF_DIV_2;
|
|
} else if (val == base_freq/4) {
|
|
rx[1] |= SCA3000_OUT_CTRL_BUF_DIV_4;
|
|
} else if (val != base_freq) {
|
|
ret = -EINVAL;
|
|
goto error_free_lock;
|
|
}
|
|
ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, rx[1]);
|
|
error_free_lock:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/* Should only really be registered if ring buffer support is compiled in.
|
|
* Does no harm however and doing it right would add a fair bit of complexity
|
|
*/
|
|
static IIO_DEV_ATTR_AVAIL_SAMP_FREQ(sca3000_read_av_freq);
|
|
|
|
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
|
sca3000_read_frequency,
|
|
sca3000_set_frequency);
|
|
|
|
|
|
/**
|
|
* sca3000_read_temp() sysfs interface to get the temperature when available
|
|
*
|
|
* The alignment of data in here is downright odd. See data sheet.
|
|
* Converting this into a meaningful value is left to inline functions in
|
|
* userspace part of header.
|
|
**/
|
|
static ssize_t sca3000_read_temp(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
int len = 0, ret;
|
|
int val;
|
|
u8 *rx;
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_TEMP_MSB, &rx, 2);
|
|
if (ret < 0)
|
|
goto error_ret;
|
|
val = ((rx[1]&0x3F) << 3) | ((rx[2] & 0xE0) >> 5);
|
|
len += sprintf(buf + len, "%d\n", val);
|
|
kfree(rx);
|
|
|
|
return len;
|
|
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
static IIO_DEV_ATTR_TEMP(sca3000_read_temp);
|
|
|
|
/**
|
|
* sca3000_show_thresh() sysfs query of a theshold
|
|
**/
|
|
static ssize_t sca3000_show_thresh(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
|
int len = 0, ret;
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_ctrl_reg(st,
|
|
this_attr->address,
|
|
&rx);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
return ret;
|
|
len += sprintf(buf + len, "%d\n", rx[1]);
|
|
kfree(rx);
|
|
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_write_thresh() sysfs control of threshold
|
|
**/
|
|
static ssize_t sca3000_write_thresh(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
|
int ret;
|
|
long val;
|
|
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
return ret;
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_write_ctrl_reg(st, this_attr->address, val);
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
static IIO_DEV_ATTR_ACCEL_THRESH_X(S_IRUGO | S_IWUSR,
|
|
sca3000_show_thresh,
|
|
sca3000_write_thresh,
|
|
SCA3000_REG_CTRL_SEL_MD_X_TH);
|
|
static IIO_DEV_ATTR_ACCEL_THRESH_Y(S_IRUGO | S_IWUSR,
|
|
sca3000_show_thresh,
|
|
sca3000_write_thresh,
|
|
SCA3000_REG_CTRL_SEL_MD_Y_TH);
|
|
static IIO_DEV_ATTR_ACCEL_THRESH_Z(S_IRUGO | S_IWUSR,
|
|
sca3000_show_thresh,
|
|
sca3000_write_thresh,
|
|
SCA3000_REG_CTRL_SEL_MD_Z_TH);
|
|
|
|
static struct attribute *sca3000_attributes[] = {
|
|
&iio_dev_attr_name.dev_attr.attr,
|
|
&iio_dev_attr_revision.dev_attr.attr,
|
|
&iio_dev_attr_accel_x.dev_attr.attr,
|
|
&iio_dev_attr_accel_y.dev_attr.attr,
|
|
&iio_dev_attr_accel_z.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_x.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_y.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_z.dev_attr.attr,
|
|
&iio_dev_attr_available_measurement_modes.dev_attr.attr,
|
|
&iio_dev_attr_measurement_mode.dev_attr.attr,
|
|
&iio_dev_attr_available_sampling_frequency.dev_attr.attr,
|
|
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute *sca3000_attributes_with_temp[] = {
|
|
&iio_dev_attr_name.dev_attr.attr,
|
|
&iio_dev_attr_revision.dev_attr.attr,
|
|
&iio_dev_attr_accel_x.dev_attr.attr,
|
|
&iio_dev_attr_accel_y.dev_attr.attr,
|
|
&iio_dev_attr_accel_z.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_x.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_y.dev_attr.attr,
|
|
&iio_dev_attr_thresh_accel_z.dev_attr.attr,
|
|
&iio_dev_attr_available_measurement_modes.dev_attr.attr,
|
|
&iio_dev_attr_measurement_mode.dev_attr.attr,
|
|
&iio_dev_attr_available_sampling_frequency.dev_attr.attr,
|
|
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
|
/* Only present if temp sensor is */
|
|
&iio_dev_attr_temp.dev_attr.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group sca3000_attribute_group = {
|
|
.attrs = sca3000_attributes,
|
|
};
|
|
|
|
static const struct attribute_group sca3000_attribute_group_with_temp = {
|
|
.attrs = sca3000_attributes_with_temp,
|
|
};
|
|
|
|
/* RING RELATED interrupt handler */
|
|
/* depending on event, push to the ring buffer event chrdev or the event one */
|
|
|
|
/**
|
|
* sca3000_interrupt_handler_bh() - handling ring and non ring events
|
|
*
|
|
* This function is complicated by the fact that the devices can signify ring
|
|
* and non ring events via the same interrupt line and they can only
|
|
* be distinguished via a read of the relevant status register.
|
|
**/
|
|
static void sca3000_interrupt_handler_bh(struct work_struct *work_s)
|
|
{
|
|
struct sca3000_state *st
|
|
= container_of(work_s, struct sca3000_state,
|
|
interrupt_handler_ws);
|
|
u8 *rx;
|
|
int ret;
|
|
|
|
/* Could lead if badly timed to an extra read of status reg,
|
|
* but ensures no interrupt is missed.
|
|
*/
|
|
enable_irq(st->us->irq);
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_INT_STATUS,
|
|
&rx, 1);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
goto done;
|
|
|
|
sca3000_ring_int_process(rx[1], st->indio_dev->ring);
|
|
|
|
if (rx[1] & SCA3000_INT_STATUS_FREE_FALL)
|
|
iio_push_event(st->indio_dev, 0,
|
|
IIO_EVENT_CODE_FREE_FALL,
|
|
st->last_timestamp);
|
|
|
|
if (rx[1] & SCA3000_INT_STATUS_Y_TRIGGER)
|
|
iio_push_event(st->indio_dev, 0,
|
|
IIO_EVENT_CODE_ACCEL_Y_HIGH,
|
|
st->last_timestamp);
|
|
|
|
if (rx[1] & SCA3000_INT_STATUS_X_TRIGGER)
|
|
iio_push_event(st->indio_dev, 0,
|
|
IIO_EVENT_CODE_ACCEL_X_HIGH,
|
|
st->last_timestamp);
|
|
|
|
if (rx[1] & SCA3000_INT_STATUS_Z_TRIGGER)
|
|
iio_push_event(st->indio_dev, 0,
|
|
IIO_EVENT_CODE_ACCEL_Z_HIGH,
|
|
st->last_timestamp);
|
|
|
|
done:
|
|
kfree(rx);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* sca3000_handler_th() handles all interrupt events from device
|
|
*
|
|
* These devices deploy unified interrupt status registers meaning
|
|
* all interrupts must be handled together
|
|
**/
|
|
static int sca3000_handler_th(struct iio_dev *dev_info,
|
|
int index,
|
|
s64 timestamp,
|
|
int no_test)
|
|
{
|
|
struct sca3000_state *st = dev_info->dev_data;
|
|
|
|
st->last_timestamp = timestamp;
|
|
schedule_work(&st->interrupt_handler_ws);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* sca3000_query_mo_det() is motion detection enabled for this axis
|
|
*
|
|
* First queries if motion detection is enabled and then if this axis is
|
|
* on.
|
|
**/
|
|
static ssize_t sca3000_query_mo_det(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
struct iio_event_attr *this_attr = to_iio_event_attr(attr);
|
|
int ret, len = 0;
|
|
u8 *rx;
|
|
u8 protect_mask = 0x03;
|
|
|
|
/* read current value of mode register */
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
|
|
if ((rx[1]&protect_mask) != SCA3000_MEAS_MODE_MOT_DET)
|
|
len += sprintf(buf + len, "0\n");
|
|
else {
|
|
kfree(rx);
|
|
ret = sca3000_read_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
&rx);
|
|
if (ret)
|
|
goto error_ret;
|
|
/* only supporting logical or's for now */
|
|
len += sprintf(buf + len, "%d\n",
|
|
(rx[1] & this_attr->mask) ? 1 : 0);
|
|
}
|
|
kfree(rx);
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
/**
|
|
* sca3000_query_free_fall_mode() is free fall mode enabled
|
|
**/
|
|
static ssize_t sca3000_query_free_fall_mode(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int ret, len;
|
|
u8 *rx;
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
return ret;
|
|
len = sprintf(buf, "%d\n",
|
|
!!(rx[1] & SCA3000_FREE_FALL_DETECT));
|
|
kfree(rx);
|
|
|
|
return len;
|
|
}
|
|
/**
|
|
* sca3000_query_ring_int() is the hardware ring status interrupt enabled
|
|
**/
|
|
static ssize_t sca3000_query_ring_int(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct iio_event_attr *this_attr = to_iio_event_attr(attr);
|
|
int ret, len;
|
|
u8 *rx;
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_INT_MASK, &rx, 1);
|
|
mutex_unlock(&st->lock);
|
|
if (ret)
|
|
return ret;
|
|
len = sprintf(buf, "%d\n", (rx[1] & this_attr->mask) ? 1 : 0);
|
|
kfree(rx);
|
|
|
|
return len;
|
|
}
|
|
/**
|
|
* sca3000_set_ring_int() set state of ring status interrupt
|
|
**/
|
|
static ssize_t sca3000_set_ring_int(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
struct iio_event_attr *this_attr = to_iio_event_attr(attr);
|
|
|
|
long val;
|
|
int ret;
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_INT_MASK, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
if (val)
|
|
ret = sca3000_write_reg(st,
|
|
SCA3000_REG_ADDR_INT_MASK,
|
|
rx[1] | this_attr->mask);
|
|
else
|
|
ret = sca3000_write_reg(st,
|
|
SCA3000_REG_ADDR_INT_MASK,
|
|
rx[1] & ~this_attr->mask);
|
|
kfree(rx);
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_set_free_fall_mode() simple on off control for free fall int
|
|
*
|
|
* In these chips the free fall detector should send an interrupt if
|
|
* the device falls more than 25cm. This has not been tested due
|
|
* to fragile wiring.
|
|
**/
|
|
|
|
static ssize_t sca3000_set_free_fall_mode(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
long val;
|
|
int ret;
|
|
u8 *rx;
|
|
u8 protect_mask = SCA3000_FREE_FALL_DETECT;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
goto error_ret;
|
|
|
|
/* read current value of mode register */
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
|
|
/*if off and should be on*/
|
|
if (val && !(rx[1] & protect_mask))
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
|
|
(rx[1] | SCA3000_FREE_FALL_DETECT));
|
|
/* if on and should be off */
|
|
else if (!val && (rx[1]&protect_mask))
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
|
|
(rx[1] & ~protect_mask));
|
|
|
|
kfree(rx);
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/**
|
|
* sca3000_set_mo_det() simple on off control for motion detector
|
|
*
|
|
* This is a per axis control, but enabling any will result in the
|
|
* motion detector unit being enabled.
|
|
* N.B. enabling motion detector stops normal data acquisition.
|
|
* There is a complexity in knowing which mode to return to when
|
|
* this mode is disabled. Currently normal mode is assumed.
|
|
**/
|
|
static ssize_t sca3000_set_mo_det(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
|
struct sca3000_state *st = indio_dev->dev_data;
|
|
struct iio_event_attr *this_attr = to_iio_event_attr(attr);
|
|
long val;
|
|
int ret;
|
|
u8 *rx;
|
|
u8 protect_mask = 0x03;
|
|
ret = strict_strtol(buf, 10, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
mutex_lock(&st->lock);
|
|
/* First read the motion detector config to find out if
|
|
* this axis is on*/
|
|
ret = sca3000_read_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
&rx);
|
|
if (ret)
|
|
goto exit_point;
|
|
/* Off and should be on */
|
|
if (val && !(rx[1] & this_attr->mask)) {
|
|
ret = sca3000_write_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
rx[1] | this_attr->mask);
|
|
if (ret)
|
|
goto exit_point_free_rx;
|
|
st->mo_det_use_count++;
|
|
} else if (!val && (rx[1]&this_attr->mask)) {
|
|
ret = sca3000_write_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
rx[1] & ~(this_attr->mask));
|
|
if (ret)
|
|
goto exit_point_free_rx;
|
|
st->mo_det_use_count--;
|
|
} else /* relies on clean state for device on boot */
|
|
goto exit_point_free_rx;
|
|
kfree(rx);
|
|
/* read current value of mode register */
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_MODE, &rx, 1);
|
|
if (ret)
|
|
goto exit_point;
|
|
/*if off and should be on*/
|
|
if ((st->mo_det_use_count)
|
|
&& ((rx[1]&protect_mask) != SCA3000_MEAS_MODE_MOT_DET))
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
|
|
(rx[1] & ~protect_mask)
|
|
| SCA3000_MEAS_MODE_MOT_DET);
|
|
/* if on and should be off */
|
|
else if (!(st->mo_det_use_count)
|
|
&& ((rx[1]&protect_mask) == SCA3000_MEAS_MODE_MOT_DET))
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
|
|
(rx[1] & ~protect_mask));
|
|
exit_point_free_rx:
|
|
kfree(rx);
|
|
exit_point:
|
|
mutex_unlock(&st->lock);
|
|
|
|
return ret ? ret : len;
|
|
}
|
|
|
|
/* Shared event handler for all events as single event status register */
|
|
IIO_EVENT_SH(all, &sca3000_handler_th);
|
|
|
|
/* Free fall detector related event attribute */
|
|
IIO_EVENT_ATTR_FREE_FALL_DETECT_SH(iio_event_all,
|
|
sca3000_query_free_fall_mode,
|
|
sca3000_set_free_fall_mode,
|
|
0)
|
|
|
|
/* Motion detector related event attributes */
|
|
IIO_EVENT_ATTR_ACCEL_X_HIGH_SH(iio_event_all,
|
|
sca3000_query_mo_det,
|
|
sca3000_set_mo_det,
|
|
SCA3000_MD_CTRL_OR_X);
|
|
|
|
IIO_EVENT_ATTR_ACCEL_Y_HIGH_SH(iio_event_all,
|
|
sca3000_query_mo_det,
|
|
sca3000_set_mo_det,
|
|
SCA3000_MD_CTRL_OR_Y);
|
|
|
|
IIO_EVENT_ATTR_ACCEL_Z_HIGH_SH(iio_event_all,
|
|
sca3000_query_mo_det,
|
|
sca3000_set_mo_det,
|
|
SCA3000_MD_CTRL_OR_Z);
|
|
|
|
/* Hardware ring buffer related event attributes */
|
|
IIO_EVENT_ATTR_RING_50_FULL_SH(iio_event_all,
|
|
sca3000_query_ring_int,
|
|
sca3000_set_ring_int,
|
|
SCA3000_INT_MASK_RING_HALF);
|
|
|
|
IIO_EVENT_ATTR_RING_75_FULL_SH(iio_event_all,
|
|
sca3000_query_ring_int,
|
|
sca3000_set_ring_int,
|
|
SCA3000_INT_MASK_RING_THREE_QUARTER);
|
|
|
|
static struct attribute *sca3000_event_attributes[] = {
|
|
&iio_event_attr_free_fall.dev_attr.attr,
|
|
&iio_event_attr_accel_x_high.dev_attr.attr,
|
|
&iio_event_attr_accel_y_high.dev_attr.attr,
|
|
&iio_event_attr_accel_z_high.dev_attr.attr,
|
|
&iio_event_attr_ring_50_full.dev_attr.attr,
|
|
&iio_event_attr_ring_75_full.dev_attr.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group sca3000_event_attribute_group = {
|
|
.attrs = sca3000_event_attributes,
|
|
};
|
|
|
|
/**
|
|
* sca3000_clean_setup() get the device into a predictable state
|
|
*
|
|
* Devices use flash memory to store many of the register values
|
|
* and hence can come up in somewhat unpredictable states.
|
|
* Hence reset everything on driver load.
|
|
**/
|
|
static int sca3000_clean_setup(struct sca3000_state *st)
|
|
{
|
|
int ret;
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
/* Ensure all interrupts have been acknowledged */
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_INT_STATUS, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
kfree(rx);
|
|
|
|
/* Turn off all motion detection channels */
|
|
ret = sca3000_read_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
&rx);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_write_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_MD_CTRL,
|
|
rx[1] & SCA3000_MD_CTRL_PROT_MASK);
|
|
kfree(rx);
|
|
if (ret)
|
|
goto error_ret;
|
|
|
|
/* Disable ring buffer */
|
|
sca3000_read_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_OUT_CTRL,
|
|
&rx);
|
|
/* Frequency of ring buffer sampling deliberately restricted to make
|
|
* debugging easier - add control of this later */
|
|
ret = sca3000_write_ctrl_reg(st,
|
|
SCA3000_REG_CTRL_SEL_OUT_CTRL,
|
|
(rx[1] & SCA3000_OUT_CTRL_PROT_MASK)
|
|
| SCA3000_OUT_CTRL_BUF_X_EN
|
|
| SCA3000_OUT_CTRL_BUF_Y_EN
|
|
| SCA3000_OUT_CTRL_BUF_Z_EN
|
|
| SCA3000_OUT_CTRL_BUF_DIV_4);
|
|
kfree(rx);
|
|
|
|
if (ret)
|
|
goto error_ret;
|
|
/* Enable interrupts, relevant to mode and set up as active low */
|
|
ret = sca3000_read_data(st,
|
|
SCA3000_REG_ADDR_INT_MASK,
|
|
&rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_write_reg(st,
|
|
SCA3000_REG_ADDR_INT_MASK,
|
|
(rx[1] & SCA3000_INT_MASK_PROT_MASK)
|
|
| SCA3000_INT_MASK_ACTIVE_LOW);
|
|
kfree(rx);
|
|
if (ret)
|
|
goto error_ret;
|
|
/* Select normal measurement mode, free fall off, ring off */
|
|
/* Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5
|
|
* as that occurs in one of the example on the datasheet */
|
|
ret = sca3000_read_data(st,
|
|
SCA3000_REG_ADDR_MODE,
|
|
&rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_write_reg(st,
|
|
SCA3000_REG_ADDR_MODE,
|
|
(rx[1] & SCA3000_MODE_PROT_MASK));
|
|
kfree(rx);
|
|
st->bpse = 11;
|
|
|
|
error_ret:
|
|
mutex_unlock(&st->lock);
|
|
return ret;
|
|
}
|
|
|
|
static int __devinit __sca3000_probe(struct spi_device *spi,
|
|
enum sca3000_variant variant)
|
|
{
|
|
int ret, regdone = 0;
|
|
struct sca3000_state *st;
|
|
|
|
st = kzalloc(sizeof(struct sca3000_state), GFP_KERNEL);
|
|
if (st == NULL) {
|
|
ret = -ENOMEM;
|
|
goto error_ret;
|
|
}
|
|
spi_set_drvdata(spi, st);
|
|
|
|
st->tx = kmalloc(sizeof(*st->tx)*6, GFP_KERNEL);
|
|
if (st->tx == NULL) {
|
|
ret = -ENOMEM;
|
|
goto error_clear_st;
|
|
}
|
|
st->rx = kmalloc(sizeof(*st->rx)*3, GFP_KERNEL);
|
|
if (st->rx == NULL) {
|
|
ret = -ENOMEM;
|
|
goto error_free_tx;
|
|
}
|
|
st->us = spi;
|
|
mutex_init(&st->lock);
|
|
st->info = &sca3000_spi_chip_info_tbl[variant];
|
|
|
|
st->indio_dev = iio_allocate_device();
|
|
if (st->indio_dev == NULL) {
|
|
ret = -ENOMEM;
|
|
goto error_free_rx;
|
|
}
|
|
|
|
st->indio_dev->dev.parent = &spi->dev;
|
|
st->indio_dev->num_interrupt_lines = 1;
|
|
st->indio_dev->event_attrs = &sca3000_event_attribute_group;
|
|
if (st->info->temp_output)
|
|
st->indio_dev->attrs = &sca3000_attribute_group_with_temp;
|
|
else
|
|
st->indio_dev->attrs = &sca3000_attribute_group;
|
|
st->indio_dev->dev_data = (void *)(st);
|
|
st->indio_dev->modes = INDIO_DIRECT_MODE;
|
|
|
|
sca3000_configure_ring(st->indio_dev);
|
|
|
|
ret = iio_device_register(st->indio_dev);
|
|
if (ret < 0)
|
|
goto error_free_dev;
|
|
regdone = 1;
|
|
ret = iio_ring_buffer_register(st->indio_dev->ring);
|
|
if (ret < 0)
|
|
goto error_unregister_dev;
|
|
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
|
|
INIT_WORK(&st->interrupt_handler_ws,
|
|
sca3000_interrupt_handler_bh);
|
|
ret = iio_register_interrupt_line(spi->irq,
|
|
st->indio_dev,
|
|
0,
|
|
IRQF_TRIGGER_FALLING,
|
|
"sca3000");
|
|
if (ret)
|
|
goto error_unregister_ring;
|
|
/* RFC
|
|
* Probably a common situation. All interrupts need an ack
|
|
* and there is only one handler so the complicated list system
|
|
* is overkill. At very least a simpler registration method
|
|
* might be worthwhile.
|
|
*/
|
|
iio_add_event_to_list(iio_event_attr_accel_z_high.listel,
|
|
&st->indio_dev
|
|
->interrupts[0]->ev_list);
|
|
}
|
|
sca3000_register_ring_funcs(st->indio_dev);
|
|
ret = sca3000_clean_setup(st);
|
|
if (ret)
|
|
goto error_unregister_interrupt_line;
|
|
return 0;
|
|
|
|
error_unregister_interrupt_line:
|
|
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
|
|
iio_unregister_interrupt_line(st->indio_dev, 0);
|
|
error_unregister_ring:
|
|
iio_ring_buffer_unregister(st->indio_dev->ring);
|
|
error_unregister_dev:
|
|
error_free_dev:
|
|
if (regdone)
|
|
iio_device_unregister(st->indio_dev);
|
|
else
|
|
iio_free_device(st->indio_dev);
|
|
error_free_rx:
|
|
kfree(st->rx);
|
|
error_free_tx:
|
|
kfree(st->tx);
|
|
error_clear_st:
|
|
kfree(st);
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
static int sca3000_stop_all_interrupts(struct sca3000_state *st)
|
|
{
|
|
int ret;
|
|
u8 *rx;
|
|
|
|
mutex_lock(&st->lock);
|
|
ret = sca3000_read_data(st, SCA3000_REG_ADDR_INT_MASK, &rx, 1);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_INT_MASK,
|
|
(rx[1] & ~(SCA3000_INT_MASK_RING_THREE_QUARTER
|
|
| SCA3000_INT_MASK_RING_HALF
|
|
| SCA3000_INT_MASK_ALL_INTS)));
|
|
error_ret:
|
|
kfree(rx);
|
|
return ret;
|
|
|
|
}
|
|
|
|
static int sca3000_remove(struct spi_device *spi)
|
|
{
|
|
struct sca3000_state *st = spi_get_drvdata(spi);
|
|
struct iio_dev *indio_dev = st->indio_dev;
|
|
int ret;
|
|
/* Must ensure no interrupts can be generated after this!*/
|
|
ret = sca3000_stop_all_interrupts(st);
|
|
if (ret)
|
|
return ret;
|
|
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
|
|
iio_unregister_interrupt_line(indio_dev, 0);
|
|
iio_ring_buffer_unregister(indio_dev->ring);
|
|
sca3000_unconfigure_ring(indio_dev);
|
|
iio_device_unregister(indio_dev);
|
|
|
|
kfree(st->tx);
|
|
kfree(st->rx);
|
|
kfree(st);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* These macros save on an awful lot of repeated code */
|
|
#define SCA3000_VARIANT_PROBE(_name) \
|
|
static int __devinit \
|
|
sca3000_##_name##_probe(struct spi_device *spi) \
|
|
{ \
|
|
return __sca3000_probe(spi, _name); \
|
|
}
|
|
|
|
#define SCA3000_VARIANT_SPI_DRIVER(_name) \
|
|
struct spi_driver sca3000_##_name##_driver = { \
|
|
.driver = { \
|
|
.name = "sca3000_" #_name, \
|
|
.owner = THIS_MODULE, \
|
|
}, \
|
|
.probe = sca3000_##_name##_probe, \
|
|
.remove = __devexit_p(sca3000_remove), \
|
|
}
|
|
|
|
SCA3000_VARIANT_PROBE(d01);
|
|
static SCA3000_VARIANT_SPI_DRIVER(d01);
|
|
|
|
SCA3000_VARIANT_PROBE(d03);
|
|
static SCA3000_VARIANT_SPI_DRIVER(d03);
|
|
|
|
SCA3000_VARIANT_PROBE(e02);
|
|
static SCA3000_VARIANT_SPI_DRIVER(e02);
|
|
|
|
SCA3000_VARIANT_PROBE(e04);
|
|
static SCA3000_VARIANT_SPI_DRIVER(e04);
|
|
|
|
SCA3000_VARIANT_PROBE(e05);
|
|
static SCA3000_VARIANT_SPI_DRIVER(e05);
|
|
|
|
SCA3000_VARIANT_PROBE(l01);
|
|
static SCA3000_VARIANT_SPI_DRIVER(l01);
|
|
|
|
static __init int sca3000_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = spi_register_driver(&sca3000_d01_driver);
|
|
if (ret)
|
|
goto error_ret;
|
|
ret = spi_register_driver(&sca3000_d03_driver);
|
|
if (ret)
|
|
goto error_unreg_d01;
|
|
ret = spi_register_driver(&sca3000_e02_driver);
|
|
if (ret)
|
|
goto error_unreg_d03;
|
|
ret = spi_register_driver(&sca3000_e04_driver);
|
|
if (ret)
|
|
goto error_unreg_e02;
|
|
ret = spi_register_driver(&sca3000_e05_driver);
|
|
if (ret)
|
|
goto error_unreg_e04;
|
|
ret = spi_register_driver(&sca3000_l01_driver);
|
|
if (ret)
|
|
goto error_unreg_e05;
|
|
|
|
return 0;
|
|
|
|
error_unreg_e05:
|
|
spi_unregister_driver(&sca3000_e05_driver);
|
|
error_unreg_e04:
|
|
spi_unregister_driver(&sca3000_e04_driver);
|
|
error_unreg_e02:
|
|
spi_unregister_driver(&sca3000_e02_driver);
|
|
error_unreg_d03:
|
|
spi_unregister_driver(&sca3000_d03_driver);
|
|
error_unreg_d01:
|
|
spi_unregister_driver(&sca3000_d01_driver);
|
|
error_ret:
|
|
|
|
return ret;
|
|
}
|
|
|
|
static __exit void sca3000_exit(void)
|
|
{
|
|
spi_unregister_driver(&sca3000_l01_driver);
|
|
spi_unregister_driver(&sca3000_e05_driver);
|
|
spi_unregister_driver(&sca3000_e04_driver);
|
|
spi_unregister_driver(&sca3000_e02_driver);
|
|
spi_unregister_driver(&sca3000_d03_driver);
|
|
spi_unregister_driver(&sca3000_d01_driver);
|
|
}
|
|
|
|
module_init(sca3000_init);
|
|
module_exit(sca3000_exit);
|
|
|
|
MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
|
|
MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver");
|
|
MODULE_LICENSE("GPL v2");
|