Commit 66533b48 authored by Jonathan Cameron's avatar Jonathan Cameron Committed by Greg Kroah-Hartman

Staging: IIO: lis3l02dq accelerometer core support

A later patch in the series will add data ready triggering
and ring buffer support.

This core patch provides an event interface and sysfs
based reading of values.
Signed-off-by: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 78632b60
......@@ -11,6 +11,7 @@ menuconfig IIO
Documentation/industrialio for more information.
if IIO
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/light/Kconfig"
......
......@@ -5,5 +5,6 @@
obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o
obj-y += accel/
obj-y += adc/
obj-y += light/
\ No newline at end of file
#
# Accelerometer drivers
#
comment "Accelerometers"
config LIS3L02DQ
tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
depends on SPI
help
Say yes here to build SPI support for the ST microelectronics
accelerometer. The driver supplies direct access via sysfs files
and an event interface via a character device.
#
# Makefile for industrial I/O accelerometer drivers
#
lis3l02dq-y := lis3l02dq_core.o
obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o
#include "../sysfs.h"
/* Accelerometer types of attribute */
#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_X_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_x_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_Y_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_y_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_Z_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(accel_z_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \
IIO_DEVICE_ATTR(accel_x, S_IRUGO, _show, NULL, _addr)
#define IIO_DEV_ATTR_ACCEL_Y(_show, _addr) \
IIO_DEVICE_ATTR(accel_y, S_IRUGO, _show, NULL, _addr)
#define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \
IIO_DEVICE_ATTR(accel_z, S_IRUGO, _show, NULL, _addr)
/* Thresholds are somewhat chip dependent - may need quite a few defs here */
/* For unified thesholds (shared across all directions */
/**
* IIO_DEV_ATTR_ACCEL_THRESH: unified threshold
* @_mode: read/write
* @_show: read detector threshold value
* @_store: write detector theshold value
* @_addr: driver specific data, typically a register address
*
* This one is for cases where as single threshold covers all directions
**/
#define IIO_DEV_ATTR_ACCEL_THRESH(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(thresh, _mode, _show, _store, _addr)
/**
* IIO_DEV_ATTR_ACCEL_THRESH_X: independant direction threshold, x axis
* @_mode: readable / writable
* @_show: read x axis detector theshold value
* @_store: write x axis detector threshold value
* @_addr: device driver dependant, typically a register address
**/
#define IIO_DEV_ATTR_ACCEL_THRESH_X(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(thresh_accel_x, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_THRESH_Y(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(thresh_accel_y, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACCEL_THRESH_Z(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(thresh_accel_z, _mode, _show, _store, _addr)
/**
* IIO_EVENT_ATTR_ACCEL_X_HIGH: threshold event, x acceleration
* @_show: read x acceleration high threshold
* @_store: write x acceleration high threshold
* @_mask: device dependant, typically a bit mask
* @_handler: the iio_handler associated with this attribute
**/
#define IIO_EVENT_ATTR_ACCEL_X_HIGH(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_x_high, _show, _store, _mask, _handler)
/**
* IIO_EVENT_ATTR_ACCEL_X_HIGH_SH: threshold event, x accel high, shared handler
* @_evlist: event list used to share the handler
* @_show: attribute read
* @_store: attribute write
* @_mask: driver specific data, typically a bit mask
**/
#define IIO_EVENT_ATTR_ACCEL_X_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_x_high, _evlist, _show, _store, _mask)
/**
* IIO_EVENT_CODE_ACCEL_X_HIGH - event code for x axis high accel threshold
**/
#define IIO_EVENT_CODE_ACCEL_X_HIGH IIO_EVENT_CODE_ACCEL_BASE
#define IIO_EVENT_ATTR_ACCEL_Y_HIGH(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_y_high, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_ACCEL_Y_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_y_high, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Y_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 1)
#define IIO_EVENT_ATTR_ACCEL_Z_HIGH(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_z_high, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_ACCEL_Z_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_z_high, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Z_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 2)
#define IIO_EVENT_ATTR_ACCEL_X_LOW(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_x_low, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_ACCEL_X_LOW_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_x_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_X_LOW (IIO_EVENT_CODE_ACCEL_BASE + 3)
#define IIO_EVENT_ATTR_ACCEL_Y_LOW(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_y_low, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_ACCEL_Y_LOW_SH(_evlist, _show, _store, _mask)\
IIO_EVENT_ATTR_SH(accel_y_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Y_LOW (IIO_EVENT_CODE_ACCEL_BASE + 4)
#define IIO_EVENT_ATTR_ACCEL_Z_LOW(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(accel_z_low, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_ACCEL_Z_LOW_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_z_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Z_LOW (IIO_EVENT_CODE_ACCEL_BASE + 5)
#define IIO_EVENT_ATTR_FREE_FALL_DETECT(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(free_fall, _show, _store, _mask, _handler)
#define IIO_EVENT_ATTR_FREE_FALL_DETECT_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(free_fall, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_FREE_FALL (IIO_EVENT_CODE_ACCEL_BASE + 6)
#define IIO_EVENT_ATTR_ACCEL_X_ROC_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_x_roc_high, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_X_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 10)
#define IIO_EVENT_ATTR_ACCEL_X_ROC_LOW_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_x_roc_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_X_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 11)
#define IIO_EVENT_ATTR_ACCEL_Y_ROC_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_y_roc_high, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Y_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 12)
#define IIO_EVENT_ATTR_ACCEL_Y_ROC_LOW_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_y_roc_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Y_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 13)
#define IIO_EVENT_ATTR_ACCEL_Z_ROC_HIGH_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_z_roc_high, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Z_ROC_HIGH (IIO_EVENT_CODE_ACCEL_BASE + 14)
#define IIO_EVENT_ATTR_ACCEL_Z_ROC_LOW_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(accel_z_roc_low, _evlist, _show, _store, _mask)
#define IIO_EVENT_CODE_ACCEL_Z_ROC_LOW (IIO_EVENT_CODE_ACCEL_BASE + 15)
/*
* LISL02DQ.h -- support STMicroelectronics LISD02DQ
* 3d 2g Linear Accelerometers via SPI
*
* Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
*
* Loosely based upon tle62x0.c
*
* 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.
*/
#ifndef SPI_LIS3L02DQ_H_
#define SPI_LIS3L02DQ_H_
#define LIS3L02DQ_READ_REG(a) ((a) | 0x80)
#define LIS3L02DQ_WRITE_REG(a) a
/* Calibration parameters */
#define LIS3L02DQ_REG_OFFSET_X_ADDR 0x16
#define LIS3L02DQ_REG_OFFSET_Y_ADDR 0x17
#define LIS3L02DQ_REG_OFFSET_Z_ADDR 0x18
#define LIS3L02DQ_REG_GAIN_X_ADDR 0x19
#define LIS3L02DQ_REG_GAIN_Y_ADDR 0x1A
#define LIS3L02DQ_REG_GAIN_Z_ADDR 0x1B
/* Control Register (1 of 2) */
#define LIS3L02DQ_REG_CTRL_1_ADDR 0x20
/* Power ctrl - either bit set corresponds to on*/
#define LIS3L02DQ_REG_CTRL_1_PD_ON 0xC0
/* Decimation Factor */
#define LIS3L02DQ_DEC_MASK 0x30
#define LIS3L02DQ_REG_CTRL_1_DF_128 0x00
#define LIS3L02DQ_REG_CTRL_1_DF_64 0x10
#define LIS3L02DQ_REG_CTRL_1_DF_32 0x20
#define LIS3L02DQ_REG_CTRL_1_DF_8 (0x10 | 0x20)
/* Self Test Enable */
#define LIS3L02DQ_REG_CTRL_1_SELF_TEST_ON 0x08
/* Axes enable ctrls */
#define LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE 0x04
#define LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE 0x02
#define LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE 0x01
/* Control Register (2 of 2) */
#define LIS3L02DQ_REG_CTRL_2_ADDR 0x21
/* Block Data Update only after MSB and LSB read */
#define LIS3L02DQ_REG_CTRL_2_BLOCK_UPDATE 0x40
/* Set to big endian output */
#define LIS3L02DQ_REG_CTRL_2_BIG_ENDIAN 0x20
/* Reboot memory content */
#define LIS3L02DQ_REG_CTRL_2_REBOOT_MEMORY 0x10
/* Interupt Enable - applies data ready to the RDY pad */
#define LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT 0x08
/* Enable Data Ready Generation - relationship with previous unclear in docs */
#define LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION 0x04
/* SPI 3 wire mode */
#define LIS3L02DQ_REG_CTRL_2_THREE_WIRE_SPI_MODE 0x02
/* Data alignment, default is 12 bit right justified
* - option for 16 bit left justified */
#define LIS3L02DQ_REG_CTRL_2_DATA_ALIGNMENT_16_BIT_LEFT_JUSTIFIED 0x01
/* Interupt related stuff */
#define LIS3L02DQ_REG_WAKE_UP_CFG_ADDR 0x23
/* Switch from or combination fo conditions to and */
#define LIS3L02DQ_REG_WAKE_UP_CFG_BOOLEAN_AND 0x80
/* Latch interupt request,
* if on ack must be given by reading the ack register */
#define LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC 0x40
/* Z Interupt on High (above threshold)*/
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH 0x20
/* Z Interupt on Low */
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW 0x10
/* Y Interupt on High */
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_HIGH 0x08
/* Y Interupt on Low */
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_LOW 0x04
/* X Interupt on High */
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_HIGH 0x02
/* X Interupt on Low */
#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_LOW 0x01
/* Register that gives description of what caused interupt
* - latched if set in CFG_ADDRES */
#define LIS3L02DQ_REG_WAKE_UP_SRC_ADDR 0x24
/* top bit ignored */
/* Interupt Active */
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_ACTIVATED 0x40
/* Interupts that have been triggered */
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH 0x20
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW 0x10
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH 0x08
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW 0x04
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH 0x02
#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW 0x01
#define LIS3L02DQ_REG_WAKE_UP_ACK_ADDR 0x25
/* Status register */
#define LIS3L02DQ_REG_STATUS_ADDR 0x27
/* XYZ axis data overrun - first is all overrun? */
#define LIS3L02DQ_REG_STATUS_XYZ_OVERRUN 0x80
#define LIS3L02DQ_REG_STATUS_Z_OVERRUN 0x40
#define LIS3L02DQ_REG_STATUS_Y_OVERRUN 0x20
#define LIS3L02DQ_REG_STATUS_X_OVERRUN 0x10
/* XYZ new data available - first is all 3 available? */
#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA 0x08
#define LIS3L02DQ_REG_STATUS_Z_NEW_DATA 0x04
#define LIS3L02DQ_REG_STATUS_Y_NEW_DATA 0x02
#define LIS3L02DQ_REG_STATUS_X_NEW_DATA 0x01
/* The accelerometer readings - low and high bytes.
Form of high byte dependant on justification set in ctrl reg */
#define LIS3L02DQ_REG_OUT_X_L_ADDR 0x28
#define LIS3L02DQ_REG_OUT_X_H_ADDR 0x29
#define LIS3L02DQ_REG_OUT_Y_L_ADDR 0x2A
#define LIS3L02DQ_REG_OUT_Y_H_ADDR 0x2B
#define LIS3L02DQ_REG_OUT_Z_L_ADDR 0x2C
#define LIS3L02DQ_REG_OUT_Z_H_ADDR 0x2D
/* Threshold values for all axes and both above and below thresholds
* - i.e. there is only one value */
#define LIS3L02DQ_REG_THS_L_ADDR 0x2E
#define LIS3L02DQ_REG_THS_H_ADDR 0x2F
#define LIS3L02DQ_DEFAULT_CTRL1 (LIS3L02DQ_REG_CTRL_1_PD_ON \
| LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE \
| LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE \
| LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE \
| LIS3L02DQ_REG_CTRL_1_DF_128)
#define LIS3L02DQ_DEFAULT_CTRL2 0
#define LIS3L02DQ_MAX_TX 12
#define LIS3L02DQ_MAX_RX 12
/**
* struct lis3l02dq_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
* @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
**/
struct lis3l02dq_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
struct iio_work_cont work_cont_thresh;
bool inter;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
};
int lis3l02dq_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val);
int lis3l02dq_spi_write_reg_8(struct device *dev,
u8 reg_address,
u8 *val);
#define LIS3L02DQ_SCAN_ACC_X 0
#define LIS3L02DQ_SCAN_ACC_Y 1
#define LIS3L02DQ_SCAN_ACC_Z 2
static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) {};
static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
};
static inline ssize_t
lis3l02dq_read_accel_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
};
static int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
{
return 0;
};
static inline void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev)
{};
static inline int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring)
{
return 0;
};
static inline void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring) {};
#endif /* SPI_LIS3L02DQ_H_ */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment