1 /* 2 * lis3lv02d_spi - SPI glue layer for lis3lv02d 3 * 4 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * publishhed by the Free Software Foundation. 9 */ 10 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/init.h> 14 #include <linux/err.h> 15 #include <linux/input.h> 16 #include <linux/interrupt.h> 17 #include <linux/workqueue.h> 18 #include <linux/spi/spi.h> 19 #include <linux/pm.h> 20 21 #include "lis3lv02d.h" 22 23 #define DRV_NAME "lis3lv02d_spi" 24 #define LIS3_SPI_READ 0x80 25 26 static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) 27 { 28 struct spi_device *spi = lis3->bus_priv; 29 int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); 30 if (ret < 0) 31 return -EINVAL; 32 33 *v = (u8) ret; 34 return 0; 35 } 36 37 static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) 38 { 39 u8 tmp[2] = { reg, val }; 40 struct spi_device *spi = lis3->bus_priv; 41 return spi_write(spi, tmp, sizeof(tmp)); 42 } 43 44 static int lis3_spi_init(struct lis3lv02d *lis3) 45 { 46 u8 reg; 47 int ret; 48 49 /* power up the device */ 50 ret = lis3->read(lis3, CTRL_REG1, ®); 51 if (ret < 0) 52 return ret; 53 54 reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; 55 return lis3->write(lis3, CTRL_REG1, reg); 56 } 57 58 static union axis_conversion lis3lv02d_axis_normal = 59 { .as_array = { 1, 2, 3 } }; 60 61 static int __devinit lis302dl_spi_probe(struct spi_device *spi) 62 { 63 int ret; 64 65 spi->bits_per_word = 8; 66 spi->mode = SPI_MODE_0; 67 ret = spi_setup(spi); 68 if (ret < 0) 69 return ret; 70 71 lis3_dev.bus_priv = spi; 72 lis3_dev.init = lis3_spi_init; 73 lis3_dev.read = lis3_spi_read; 74 lis3_dev.write = lis3_spi_write; 75 lis3_dev.irq = spi->irq; 76 lis3_dev.ac = lis3lv02d_axis_normal; 77 lis3_dev.pdata = spi->dev.platform_data; 78 spi_set_drvdata(spi, &lis3_dev); 79 80 return lis3lv02d_init_device(&lis3_dev); 81 } 82 83 static int __devexit lis302dl_spi_remove(struct spi_device *spi) 84 { 85 struct lis3lv02d *lis3 = spi_get_drvdata(spi); 86 lis3lv02d_joystick_disable(lis3); 87 lis3lv02d_poweroff(lis3); 88 89 return lis3lv02d_remove_fs(&lis3_dev); 90 } 91 92 #ifdef CONFIG_PM_SLEEP 93 static int lis3lv02d_spi_suspend(struct device *dev) 94 { 95 struct spi_device *spi = to_spi_device(dev); 96 struct lis3lv02d *lis3 = spi_get_drvdata(spi); 97 98 if (!lis3->pdata || !lis3->pdata->wakeup_flags) 99 lis3lv02d_poweroff(&lis3_dev); 100 101 return 0; 102 } 103 104 static int lis3lv02d_spi_resume(struct device *dev) 105 { 106 struct spi_device *spi = to_spi_device(dev); 107 struct lis3lv02d *lis3 = spi_get_drvdata(spi); 108 109 if (!lis3->pdata || !lis3->pdata->wakeup_flags) 110 lis3lv02d_poweron(lis3); 111 112 return 0; 113 } 114 #endif 115 116 static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, 117 lis3lv02d_spi_resume); 118 119 static struct spi_driver lis302dl_spi_driver = { 120 .driver = { 121 .name = DRV_NAME, 122 .owner = THIS_MODULE, 123 .pm = &lis3lv02d_spi_pm, 124 }, 125 .probe = lis302dl_spi_probe, 126 .remove = __devexit_p(lis302dl_spi_remove), 127 }; 128 129 module_spi_driver(lis302dl_spi_driver); 130 131 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 132 MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); 133 MODULE_LICENSE("GPL"); 134 MODULE_ALIAS("spi:" DRV_NAME); 135