Skip to content

Commit

Permalink
Input: add driver for ADXL345/346 Digital Accelerometers
Browse files Browse the repository at this point in the history
This is a driver for the ADXL345/346 Three-Axis Digital Accelerometers.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Chris Verges <chrisv@cyberswitching.com>
Signed-off-by: Luotao Fu <l.fu@pengutronix.de>
Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
  • Loading branch information
mhennerich authored and dtor committed Jun 25, 2010
1 parent 69a4af6 commit e27c729
Show file tree
Hide file tree
Showing 7 changed files with 1,511 additions and 0 deletions.
37 changes: 37 additions & 0 deletions drivers/input/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,41 @@ config INPUT_PCAP
To compile this driver as a module, choose M here: the
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
3 changes: 3 additions & 0 deletions drivers/input/misc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.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_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
Expand Down
163 changes: 163 additions & 0 deletions drivers/input/misc/adxl34x-i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* 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");
145 changes: 145 additions & 0 deletions drivers/input/misc/adxl34x-spi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* 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");
Loading

0 comments on commit e27c729

Please sign in to comment.