-
Notifications
You must be signed in to change notification settings - Fork 54.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Input: add driver for ADXL345/346 Digital Accelerometers
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
1 parent
69a4af6
commit e27c729
Showing
7 changed files
with
1,511 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, ®, 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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, ®, 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"); |
Oops, something went wrong.