Commit e27c7292 authored by Michael Hennerich's avatar Michael Hennerich Committed by Dmitry Torokhov

Input: add driver for ADXL345/346 Digital Accelerometers

This is a driver for the ADXL345/346 Three-Axis Digital Accelerometers.
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarChris Verges <chrisv@cyberswitching.com>
Signed-off-by: default avatarLuotao Fu <l.fu@pengutronix.de>
Signed-off-by: default avatarBarry Song <barry.song@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 69a4af60
...@@ -390,4 +390,41 @@ config INPUT_PCAP ...@@ -390,4 +390,41 @@ config INPUT_PCAP
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called pcap_keys. module will be called pcap_keys.
config INPUT_ADXL34X
tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
default n
help
Say Y here if you have a Accelerometer interface using the
ADXL345/6 controller, and your board-specific initialization
code includes that in its table of devices.
This driver can use either I2C or SPI communication to the
ADXL345/6 controller. Select the appropriate method for
your system.
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 adxl34x.
config INPUT_ADXL34X_I2C
tristate "support I2C bus connection"
depends on INPUT_ADXL34X && I2C
default y
help
Say Y here if you have ADXL345/6 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called adxl34x-i2c.
config INPUT_ADXL34X_SPI
tristate "support SPI bus connection"
depends on INPUT_ADXL34X && SPI
default y
help
Say Y here if you have ADXL345/6 hooked to a SPI bus.
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
endif endif
...@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o ...@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o
obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o
obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
......
/*
* ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include "adxl34x.h"
static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_read_byte_data(client, reg);
}
static int adxl34x_smbus_write(struct device *dev,
unsigned char reg, unsigned char val)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_write_byte_data(client, reg, val);
}
static int adxl34x_smbus_read_block(struct device *dev,
unsigned char reg, int count,
void *buf)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
}
static int adxl34x_i2c_read_block(struct device *dev,
unsigned char reg, int count,
void *buf)
{
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_master_send(client, &reg, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(client, buf, count);
if (ret < 0)
return ret;
if (ret != count)
return -EIO;
return 0;
}
static const struct adxl34x_bus_ops adx134x_smbus_bops = {
.bustype = BUS_I2C,
.write = adxl34x_smbus_write,
.read = adxl34x_smbus_read,
.read_block = adxl34x_smbus_read_block,
};
static const struct adxl34x_bus_ops adx134x_i2c_bops = {
.bustype = BUS_I2C,
.write = adxl34x_smbus_write,
.read = adxl34x_smbus_read,
.read_block = adxl34x_i2c_read_block,
};
static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adxl34x *ac;
int error;
error = i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA);
if (!error) {
dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
return -EIO;
}
ac = adxl34x_probe(&client->dev, client->irq, false,
i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
&adx134x_smbus_bops : &adx134x_i2c_bops);
if (IS_ERR(ac))
return PTR_ERR(ac);
i2c_set_clientdata(client, ac);
return 0;
}
static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
{
struct adxl34x *ac = i2c_get_clientdata(client);
return adxl34x_remove(ac);
}
#ifdef CONFIG_PM
static int adxl34x_suspend(struct i2c_client *client, pm_message_t message)
{
struct adxl34x *ac = i2c_get_clientdata(client);
adxl34x_disable(ac);
return 0;
}
static int adxl34x_resume(struct i2c_client *client)
{
struct adxl34x *ac = i2c_get_clientdata(client);
adxl34x_enable(ac);
return 0;
}
#else
# define adxl34x_suspend NULL
# define adxl34x_resume NULL
#endif
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.owner = THIS_MODULE,
},
.probe = adxl34x_i2c_probe,
.remove = __devexit_p(adxl34x_i2c_remove),
.suspend = adxl34x_suspend,
.resume = adxl34x_resume,
.id_table = adxl34x_id,
};
static int __init adxl34x_i2c_init(void)
{
return i2c_add_driver(&adxl34x_driver);
}
module_init(adxl34x_i2c_init);
static void __exit adxl34x_i2c_exit(void)
{
i2c_del_driver(&adxl34x_driver);
}
module_exit(adxl34x_i2c_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
MODULE_LICENSE("GPL");
/*
* ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_SPI */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "adxl34x.h"
#define MAX_SPI_FREQ_HZ 5000000
#define MAX_FREQ_NO_FIFODELAY 1500000
#define ADXL34X_CMD_MULTB (1 << 6)
#define ADXL34X_CMD_READ (1 << 7)
#define ADXL34X_WRITECMD(reg) (reg & 0x3F)
#define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F))
#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
| (reg & 0x3F))
static int adxl34x_spi_read(struct device *dev, unsigned char reg)
{
struct spi_device *spi = to_spi_device(dev);
unsigned char cmd;
cmd = ADXL34X_READCMD(reg);
return spi_w8r8(spi, cmd);
}
static int adxl34x_spi_write(struct device *dev,
unsigned char reg, unsigned char val)
{
struct spi_device *spi = to_spi_device(dev);
unsigned char buf[2];
buf[0] = ADXL34X_WRITECMD(reg);
buf[1] = val;
return spi_write(spi, buf, sizeof(buf));
}
static int adxl34x_spi_read_block(struct device *dev,
unsigned char reg, int count,
void *buf)
{
struct spi_device *spi = to_spi_device(dev);
ssize_t status;
reg = ADXL34X_READMB_CMD(reg);
status = spi_write_then_read(spi, &reg, 1, buf, count);
return (status < 0) ? status : 0;
}
static const struct adxl34x_bus_ops adx134x_spi_bops = {
.bustype = BUS_SPI,
.write = adxl34x_spi_write,
.read = adxl34x_spi_read,
.read_block = adxl34x_spi_read_block,
};
static int __devinit adxl34x_spi_probe(struct spi_device *spi)
{
struct adxl34x *ac;
/* don't exceed max specified SPI CLK frequency */
if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
return -EINVAL;
}
ac = adxl34x_probe(&spi->dev, spi->irq,
spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
&adx134x_spi_bops);
if (IS_ERR(ac))
return PTR_ERR(ac);
spi_set_drvdata(spi, ac);
return 0;
}
static int __devexit adxl34x_spi_remove(struct spi_device *spi)
{
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
return adxl34x_remove(ac);
}
#ifdef CONFIG_PM
static int adxl34x_suspend(struct spi_device *spi, pm_message_t message)
{
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
adxl34x_disable(ac);
return 0;
}
static int adxl34x_resume(struct spi_device *spi)
{
struct adxl34x *ac = dev_get_drvdata(&spi->dev);
adxl34x_enable(ac);
return 0;
}
#else
# define adxl34x_suspend NULL
# define adxl34x_resume NULL
#endif
static struct spi_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = adxl34x_spi_probe,
.remove = __devexit_p(adxl34x_spi_remove),
.suspend = adxl34x_suspend,
.resume = adxl34x_resume,
};
static int __init adxl34x_spi_init(void)
{
return spi_register_driver(&adxl34x_driver);
}
module_init(adxl34x_spi_init);
static void __exit adxl34x_spi_exit(void)
{
spi_unregister_driver(&adxl34x_driver);
}
module_exit(adxl34x_spi_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
MODULE_LICENSE("GPL");
This diff is collapsed.
/*
* ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
#ifndef _ADXL34X_H_
#define _ADXL34X_H_
struct device;
struct adxl34x;
struct adxl34x_bus_ops {
u16 bustype;
int (*read)(struct device *, unsigned char);
int (*read_block)(struct device *, unsigned char, int, void *);
int (*write)(struct device *, unsigned char, unsigned char);
};
void adxl34x_disable(struct adxl34x *ac);
void adxl34x_enable(struct adxl34x *ac);
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
int adxl34x_remove(struct adxl34x *ac);
#endif
/*
* include/linux/input/adxl34x.h
*
* Digital Accelerometer characteristics are highly application specific
* and may vary between boards and models. The platform_data for the
* device's "struct device" holds this information.
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __LINUX_INPUT_ADXL34X_H__
#define __LINUX_INPUT_ADXL34X_H__
struct adxl34x_platform_data {
/*
* X,Y,Z Axis Offset:
* offer user offset adjustments in twoscompliment
* form with a scale factor of 15.6 mg/LSB (i.e. 0x7F = +2 g)
*/
s8 x_axis_offset;
s8 y_axis_offset;
s8 z_axis_offset;
/*
* TAP_X/Y/Z Enable: Setting TAP_X, Y, or Z Enable enables X,
* Y, or Z participation in Tap detection. A '0' excludes the
* selected axis from participation in Tap detection.
* Setting the SUPPRESS bit suppresses Double Tap detection if
* acceleration greater than tap_threshold is present between
* taps.
*/
#define ADXL_SUPPRESS (1 << 3)
#define ADXL_TAP_X_EN (1 << 2)
#define ADXL_TAP_Y_EN (1 << 1)
#define ADXL_TAP_Z_EN (1 << 0)
u8 tap_axis_control;
/*
* tap_threshold:
* holds the threshold value for tap detection/interrupts.
* The data format is unsigned. The scale factor is 62.5 mg/LSB
* (i.e. 0xFF = +16 g). A zero value may result in undesirable
* behavior if Tap/Double Tap is enabled.
*/
u8 tap_threshold;
/*
* tap_duration:
* is an unsigned time value representing the maximum
* time that an event must be above the tap_threshold threshold
* to qualify as a tap event. The scale factor is 625 us/LSB. A zero
* value will prevent Tap/Double Tap functions from working.
*/
u8 tap_duration;
/*
* tap_latency:
* is an unsigned time value representing the wait time
* from the detection of a tap event to the opening of the time
* window tap_window for a possible second tap event. The scale
* factor is 1.25 ms/LSB. A zero value will disable the Double Tap
* function.
*/
u8 tap_latency;
/*
* tap_window:
* is an unsigned time value representing the amount
* of time after the expiration of tap_latency during which a second
* tap can begin. The scale factor is 1.25 ms/LSB. A zero value will
* disable the Double Tap function.
*/
u8 tap_window;
/*
* act_axis_control:
* X/Y/Z Enable: A '1' enables X, Y, or Z participation in activity
* or inactivity detection. A '0' excludes the selected axis from
* participation. If all of the axes are excluded, the function is
* disabled.
* AC/DC: A '0' = DC coupled operation and a '1' = AC coupled
* operation. In DC coupled operation, the current acceleration is
* compared with activity_threshold and inactivity_threshold directly
* to determine whether activity or inactivity is detected. In AC
* coupled operation for activity detection, the acceleration value
* at the start of activity detection is taken as a reference value.
* New samples of acceleration are then compared to this
* reference value and if the magnitude of the difference exceeds
* activity_threshold the device will trigger an activity interrupt. In
* AC coupled operation for inactivity detection, a reference value
* is used again for comparison and is updated whenever the
* device exceeds the inactivity threshold. Once the reference
* value is selected, the device compares the magnitude of the
* difference between the reference value and the current
* acceleration with inactivity_threshold. If the difference is below
* inactivity_threshold for a total of inactivity_time, the device is
* considered inactive and the inactivity interrupt is triggered.
*/
#define ADXL_ACT_ACDC (1 << 7)
#define ADXL_ACT_X_EN (1 << 6)
#define ADXL_ACT_Y_EN (1 << 5)
#define ADXL_ACT_Z_EN (1 << 4)
#define ADXL_INACT_ACDC (1 << 3)
#define ADXL_INACT_X_EN (1 << 2)
#define ADXL_INACT_Y_EN (1 << 1)
#define ADXL_INACT_Z_EN (1 << 0)
u8 act_axis_control;
/*
* activity_threshold:
* holds the threshold value for activity detection.
* The data format is unsigned. The scale factor is
* 62.5 mg/LSB. A zero value may result in undesirable behavior if
* Activity interrupt is enabled.
*/
u8 activity_threshold;
/*
* inactivity_threshold:
* holds the threshold value for inactivity
* detection. The data format is unsigned. The scale
* factor is 62.5 mg/LSB. A zero value may result in undesirable
* behavior if Inactivity interrupt is enabled.
*/
u8 inactivity_threshold;
/*
* inactivity_time:
* is an unsigned time value representing the
* amount of time that acceleration must be below the value in
* inactivity_threshold for inactivity to be declared. The scale factor
* is 1 second/LSB. Unlike the other interrupt functions, which
* operate on unfiltered data, the inactivity function operates on the
* filtered output data. At least one output sample must be
* generated for the inactivity interrupt to be triggered. This will
* result in the function appearing un-responsive if the
* inactivity_time register is set with a value less than the time
* constant of the Output Data Rate. A zero value will result in an
* interrupt when the output data is below inactivity_threshold.
*/
u8 inactivity_time;
/*
* free_fall_threshold:
* holds the threshold value for Free-Fall detection.
* The data format is unsigned. The root-sum-square(RSS) value
* of all axes is calculated and compared to the value in
* free_fall_threshold to determine if a free fall event may be
* occurring. The scale factor is 62.5 mg/LSB. A zero value may
* result in undesirable behavior if Free-Fall interrupt is
* enabled. Values between 300 and 600 mg (0x05 to 0x09) are
* recommended.
*/
u8 free_fall_threshold;
/*
* free_fall_time:
* is an unsigned time value representing the minimum
* time that the RSS value of all axes must be less than
* free_fall_threshold to generate a Free-Fall interrupt. The
* scale factor is 5 ms/LSB. A zero value may result in
* undesirable behavior if Free-Fall interrupt is enabled.
* Values between 100 to 350 ms (0x14 to 0x46) are recommended.
*/
u8 free_fall_time;
/*
* data_rate:
* Selects device bandwidth and output data rate.
* RATE = 3200 Hz / (2^(15 - x)). Default value is 0x0A, or 100 Hz
* Output Data Rate. An Output Data Rate should be selected that
* is appropriate for the communication protocol and frequency
* selected. Selecting too high of an Output Data Rate with a low
* communication speed will result in samples being discarded.
*/
u8 data_rate;
/*
* data_range:
* FULL_RES: When this bit is set with the device is
* in Full-Resolution Mode, where the output resolution increases
* with RANGE to maintain a 4 mg/LSB scale factor. When this
* bit is cleared the device is in 10-bit Mode and RANGE determine the
* maximum g-Range and scale factor.
*/
#define ADXL_FULL_RES (1 << 3)
#define ADXL_RANGE_PM_2g 0
#define ADXL_RANGE_PM_4g 1
#define ADXL_RANGE_PM_8g 2
#define ADXL_RANGE_PM_16g 3
u8 data_range;
/*
* low_power_mode:
* A '0' = Normal operation and a '1' = Reduced
* power operation with somewhat higher noise.
*/
u8 low_power_mode;
/*
* power_mode:
* LINK: A '1' with both the activity and inactivity functions
* enabled will delay the start of the activity function until
* inactivity is detected. Once activity is detected, inactivity
* detection will begin and prevent the detection of activity. This
* bit serially links the activity and inactivity functions. When '0'
* the inactivity and activity functions are concurrent. Additional
* information can be found in the Application section under Link
* Mode.
* AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
* when inactivity (acceleration has been below inactivity_threshold
* for at least inactivity_time) is detected and the LINK bit is set.
* A '0' disables automatic switching to Sleep Mode. See SLEEP
* for further description.
*/
#define ADXL_LINK (1 << 5)
#define ADXL_AUTO_SLEEP (1 << 4)
u8 power_mode;
/*
* fifo_mode:
* BYPASS The FIFO is bypassed
* FIFO FIFO collects up to 32 values then stops collecting data
* STREAM FIFO holds the last 32 data values. Once full, the FIFO's
* oldest data is lost as it is replaced with newer data
*
* DEFAULT should be ADXL_FIFO_STREAM
*/
#define ADXL_FIFO_BYPASS 0
#define ADXL_FIFO_FIFO 1
#define ADXL_FIFO_STREAM 2
u8 fifo_mode;
/*
* watermark:
* The Watermark feature can be used to reduce the interrupt load
* of the system. The FIFO fills up to the value stored in watermark
* [1..32] and then generates an interrupt.
* A '0' disables the watermark feature.
*/
u8 watermark;
u32 ev_type; /* EV_ABS or EV_REL */
u32 ev_code_x; /* ABS_X,Y,Z or REL_X,Y,Z */
u32 ev_code_y; /* ABS_X,Y,Z or REL_X,Y,Z */
u32 ev_code_z; /* ABS_X,Y,Z or REL_X,Y,Z */
/*
* A valid BTN or KEY Code; use tap_axis_control to disable
* event reporting
*/
u32 ev_code_tap[3]; /* EV_KEY {X-Axis, Y-Axis, Z-Axis} */
/*
* A valid BTN or KEY Code for Free-Fall or Activity enables
* input event reporting. A '0' disables the Free-Fall or
* Activity reporting.
*/
u32 ev_code_ff; /* EV_KEY */
u32 ev_code_act_inactivity; /* EV_KEY */
u8 use_int2;
};
#endif
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