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