1e27c7292SMichael Hennerich /* 2e27c7292SMichael Hennerich * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface) 3e27c7292SMichael Hennerich * 4e27c7292SMichael Hennerich * Enter bugs at http://blackfin.uclinux.org/ 5e27c7292SMichael Hennerich * 6e27c7292SMichael Hennerich * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc. 7e27c7292SMichael Hennerich * Licensed under the GPL-2 or later. 8e27c7292SMichael Hennerich */ 9e27c7292SMichael Hennerich 10e27c7292SMichael Hennerich #include <linux/input.h> /* BUS_SPI */ 11e27c7292SMichael Hennerich #include <linux/module.h> 12e27c7292SMichael Hennerich #include <linux/spi/spi.h> 134d1ac94eSMark Brown #include <linux/pm.h> 14e27c7292SMichael Hennerich #include <linux/types.h> 15e27c7292SMichael Hennerich #include "adxl34x.h" 16e27c7292SMichael Hennerich 17e27c7292SMichael Hennerich #define MAX_SPI_FREQ_HZ 5000000 18e27c7292SMichael Hennerich #define MAX_FREQ_NO_FIFODELAY 1500000 19e27c7292SMichael Hennerich #define ADXL34X_CMD_MULTB (1 << 6) 20e27c7292SMichael Hennerich #define ADXL34X_CMD_READ (1 << 7) 21e27c7292SMichael Hennerich #define ADXL34X_WRITECMD(reg) (reg & 0x3F) 22e27c7292SMichael Hennerich #define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F)) 23e27c7292SMichael Hennerich #define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \ 24e27c7292SMichael Hennerich | (reg & 0x3F)) 25e27c7292SMichael Hennerich 26e27c7292SMichael Hennerich static int adxl34x_spi_read(struct device *dev, unsigned char reg) 27e27c7292SMichael Hennerich { 28e27c7292SMichael Hennerich struct spi_device *spi = to_spi_device(dev); 29e27c7292SMichael Hennerich unsigned char cmd; 30e27c7292SMichael Hennerich 31e27c7292SMichael Hennerich cmd = ADXL34X_READCMD(reg); 32e27c7292SMichael Hennerich 33e27c7292SMichael Hennerich return spi_w8r8(spi, cmd); 34e27c7292SMichael Hennerich } 35e27c7292SMichael Hennerich 36e27c7292SMichael Hennerich static int adxl34x_spi_write(struct device *dev, 37e27c7292SMichael Hennerich unsigned char reg, unsigned char val) 38e27c7292SMichael Hennerich { 39e27c7292SMichael Hennerich struct spi_device *spi = to_spi_device(dev); 40e27c7292SMichael Hennerich unsigned char buf[2]; 41e27c7292SMichael Hennerich 42e27c7292SMichael Hennerich buf[0] = ADXL34X_WRITECMD(reg); 43e27c7292SMichael Hennerich buf[1] = val; 44e27c7292SMichael Hennerich 45e27c7292SMichael Hennerich return spi_write(spi, buf, sizeof(buf)); 46e27c7292SMichael Hennerich } 47e27c7292SMichael Hennerich 48e27c7292SMichael Hennerich static int adxl34x_spi_read_block(struct device *dev, 49e27c7292SMichael Hennerich unsigned char reg, int count, 50e27c7292SMichael Hennerich void *buf) 51e27c7292SMichael Hennerich { 52e27c7292SMichael Hennerich struct spi_device *spi = to_spi_device(dev); 53e27c7292SMichael Hennerich ssize_t status; 54e27c7292SMichael Hennerich 55e27c7292SMichael Hennerich reg = ADXL34X_READMB_CMD(reg); 56e27c7292SMichael Hennerich status = spi_write_then_read(spi, ®, 1, buf, count); 57e27c7292SMichael Hennerich 58e27c7292SMichael Hennerich return (status < 0) ? status : 0; 59e27c7292SMichael Hennerich } 60e27c7292SMichael Hennerich 613dcab3bdSMark Brown static const struct adxl34x_bus_ops adxl34x_spi_bops = { 62e27c7292SMichael Hennerich .bustype = BUS_SPI, 63e27c7292SMichael Hennerich .write = adxl34x_spi_write, 64e27c7292SMichael Hennerich .read = adxl34x_spi_read, 65e27c7292SMichael Hennerich .read_block = adxl34x_spi_read_block, 66e27c7292SMichael Hennerich }; 67e27c7292SMichael Hennerich 68e27c7292SMichael Hennerich static int __devinit adxl34x_spi_probe(struct spi_device *spi) 69e27c7292SMichael Hennerich { 70e27c7292SMichael Hennerich struct adxl34x *ac; 71e27c7292SMichael Hennerich 72e27c7292SMichael Hennerich /* don't exceed max specified SPI CLK frequency */ 73e27c7292SMichael Hennerich if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { 74e27c7292SMichael Hennerich dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz); 75e27c7292SMichael Hennerich return -EINVAL; 76e27c7292SMichael Hennerich } 77e27c7292SMichael Hennerich 78e27c7292SMichael Hennerich ac = adxl34x_probe(&spi->dev, spi->irq, 79e27c7292SMichael Hennerich spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY, 803dcab3bdSMark Brown &adxl34x_spi_bops); 81e27c7292SMichael Hennerich 82e27c7292SMichael Hennerich if (IS_ERR(ac)) 83e27c7292SMichael Hennerich return PTR_ERR(ac); 84e27c7292SMichael Hennerich 85e27c7292SMichael Hennerich spi_set_drvdata(spi, ac); 86e27c7292SMichael Hennerich 87e27c7292SMichael Hennerich return 0; 88e27c7292SMichael Hennerich } 89e27c7292SMichael Hennerich 90e27c7292SMichael Hennerich static int __devexit adxl34x_spi_remove(struct spi_device *spi) 91e27c7292SMichael Hennerich { 92e27c7292SMichael Hennerich struct adxl34x *ac = dev_get_drvdata(&spi->dev); 93e27c7292SMichael Hennerich 94e27c7292SMichael Hennerich return adxl34x_remove(ac); 95e27c7292SMichael Hennerich } 96e27c7292SMichael Hennerich 97e27c7292SMichael Hennerich #ifdef CONFIG_PM 984d1ac94eSMark Brown static int adxl34x_spi_suspend(struct device *dev) 99e27c7292SMichael Hennerich { 1004d1ac94eSMark Brown struct spi_device *spi = to_spi_device(dev); 101e27c7292SMichael Hennerich struct adxl34x *ac = dev_get_drvdata(&spi->dev); 102e27c7292SMichael Hennerich 103af6e1d99SDmitry Torokhov adxl34x_suspend(ac); 104e27c7292SMichael Hennerich 105e27c7292SMichael Hennerich return 0; 106e27c7292SMichael Hennerich } 107e27c7292SMichael Hennerich 1084d1ac94eSMark Brown static int adxl34x_spi_resume(struct device *dev) 109e27c7292SMichael Hennerich { 1104d1ac94eSMark Brown struct spi_device *spi = to_spi_device(dev); 111e27c7292SMichael Hennerich struct adxl34x *ac = dev_get_drvdata(&spi->dev); 112e27c7292SMichael Hennerich 113af6e1d99SDmitry Torokhov adxl34x_resume(ac); 114e27c7292SMichael Hennerich 115e27c7292SMichael Hennerich return 0; 116e27c7292SMichael Hennerich } 117e27c7292SMichael Hennerich #endif 118e27c7292SMichael Hennerich 1194d1ac94eSMark Brown static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend, 1204d1ac94eSMark Brown adxl34x_spi_resume); 1214d1ac94eSMark Brown 122e27c7292SMichael Hennerich static struct spi_driver adxl34x_driver = { 123e27c7292SMichael Hennerich .driver = { 124e27c7292SMichael Hennerich .name = "adxl34x", 125e27c7292SMichael Hennerich .bus = &spi_bus_type, 126e27c7292SMichael Hennerich .owner = THIS_MODULE, 1274d1ac94eSMark Brown .pm = &adxl34x_spi_pm, 128e27c7292SMichael Hennerich }, 129e27c7292SMichael Hennerich .probe = adxl34x_spi_probe, 130e27c7292SMichael Hennerich .remove = __devexit_p(adxl34x_spi_remove), 131e27c7292SMichael Hennerich }; 132e27c7292SMichael Hennerich 133e27c7292SMichael Hennerich static int __init adxl34x_spi_init(void) 134e27c7292SMichael Hennerich { 135e27c7292SMichael Hennerich return spi_register_driver(&adxl34x_driver); 136e27c7292SMichael Hennerich } 137e27c7292SMichael Hennerich module_init(adxl34x_spi_init); 138e27c7292SMichael Hennerich 139e27c7292SMichael Hennerich static void __exit adxl34x_spi_exit(void) 140e27c7292SMichael Hennerich { 141e27c7292SMichael Hennerich spi_unregister_driver(&adxl34x_driver); 142e27c7292SMichael Hennerich } 143e27c7292SMichael Hennerich module_exit(adxl34x_spi_exit); 144e27c7292SMichael Hennerich 145e27c7292SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 146e27c7292SMichael Hennerich MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver"); 147e27c7292SMichael Hennerich MODULE_LICENSE("GPL"); 148