r3125 - branches/src/target/kernel/2.6.23.x/patches
shoragan at sita.openmoko.org
shoragan at sita.openmoko.org
Tue Oct 9 17:10:30 CEST 2007
Author: shoragan
Date: 2007-10-09 17:10:29 +0200 (Tue, 09 Oct 2007)
New Revision: 3125
Added:
branches/src/target/kernel/2.6.23.x/patches/lis302dl.patch
Modified:
branches/src/target/kernel/2.6.23.x/patches/series
Log:
Follow change in 2.6.22:
(orig r3105): laforge | 2007-10-07 18:54:47 +0200
add preliminary lis302 accelerometer input device driver for GTA02
Added: branches/src/target/kernel/2.6.23.x/patches/lis302dl.patch
===================================================================
--- branches/src/target/kernel/2.6.23.x/patches/lis302dl.patch 2007-10-09 14:12:02 UTC (rev 3124)
+++ branches/src/target/kernel/2.6.23.x/patches/lis302dl.patch 2007-10-09 15:10:29 UTC (rev 3125)
@@ -0,0 +1,750 @@
+This is a Linux driver for the STmicro LIS302DL 3-axis accelerometer.
+
+Signed-off-by: Harald Welte <laforge at openmoko.org>
+
+Index: linux-2.6.22.5-moko/arch/arm/mach-s3c2440/mach-gta02.c
+===================================================================
+--- linux-2.6.22.5-moko.orig/arch/arm/mach-s3c2440/mach-gta02.c
++++ linux-2.6.22.5-moko/arch/arm/mach-s3c2440/mach-gta02.c
+@@ -310,6 +310,7 @@
+ &s3c_device_usbgadget,
+ &s3c_device_nand,
+ &s3c_device_ts,
++ &s3c_device_spi1,
+ };
+
+ static struct s3c2410_nand_set gta02_nand_sets[] = {
+@@ -439,6 +440,47 @@
+ .board_info = gta02_spi_board_info,
+ };
+
++static void gta02_spi_acc_set_cs(struct s3c2410_spi_info *spi, int cs, int pol)
++{
++ s3c2410_gpio_setpin(cs, pol);
++}
++
++static struct lis302dl_platform_data lis302_pdata[] = {
++ {
++ .name = "lis302-1 (top)"
++ }, {
++ .name = "lis302-2 (bottom)"
++ },
++};
++
++static struct spi_board_info gta02_spi_acc_bdinfo[] = {
++ {
++ .modalias = "lis302dl",
++ .platform_data = lis302_pdata[0],
++ .irq = S3C2410_EINT0,
++ .max_speed_hz = 400 * 1000,
++ .bus_num = 1,
++ .chip_select = S3C2410_GPD12,
++ .mode = SPI_MODE_3,
++ },
++ {
++ .modalias = "lis302dl",
++ .platform_data = lis302_pdata[1],
++ .irq = S3C2410_EINT16,
++ .max_speed_hz = 400 * 1000,
++ .bus_num = 1,
++ .chip_select = S3C2410_GPD13,
++ .mode = SPI_MODE_3,
++ },
++};
++
++static struct s3c2410_spi_info gta02_spi_acc_cfg = {
++ .set_cs = gta02_spi_acc_set_cs,
++ .board_size = ARRAY_SIZE(gta02_spi_acc_bdinfo),
++ .board_info = >a02_spi_acc_bdinfo,
++};
++
++
+ #if 0
+ #ifdef SPI_HARD
+ static struct s3c2410_spi_info spi_cfg = {
+@@ -628,6 +670,7 @@
+ s3c_device_usb.dev.platform_data = >a02_usb_info;
+ s3c_device_nand.dev.platform_data = >a02_nand_info;
+ s3c_device_sdi.dev.platform_data = >a02_mmc_cfg;
++ s3c_device_spi1.dev.platform_data = >a02_spi_acc_cfg;
+
+ INIT_WORK(>a02_udc_vbus_drawer.work, __gta02_udc_vbus_draw);
+ s3c24xx_udc_set_platdata(>a02_udc_cfg);
+Index: linux-2.6.22.5-moko/drivers/spi/lis302dl.c
+===================================================================
+--- /dev/null
++++ linux-2.6.22.5-moko/drivers/spi/lis302dl.c
+@@ -0,0 +1,633 @@
++/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
++ *
++ * Copyright (C) 2007 by OpenMoko, Inc.
++ * Author: Harald Welte <laforge at openmoko.org>
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ * TODO
++ * * statistics for overflow events
++ * * configuration interface (sysfs) for
++ * * enable/disable x/y/z axis data ready
++ * * enable/disable resume from freee fall / click
++ * * free fall / click parameters
++ * * high pass filter parameters
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/input.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/sysfs.h>
++
++#include <linux/lis302dl.h>
++
++#include <linux/spi/spi.h>
++
++#define LIS302DL_WHO_AM_I_MAGIC 0x3b
++
++enum lis302dl_reg {
++ LIS302DL_REG_WHO_AM_I = 0x0f,
++ LIS302DL_REG_CTRL1 = 0x20,
++ LIS302DL_REG_CTRL2 = 0x21,
++ LIS302DL_REG_CTRL3 = 0x22,
++ LIS302DL_REG_HP_FILTER_RESET = 0x23,
++ LIS302DL_REG_STATUS = 0x27,
++ LIS302DL_REG_OUT_X = 0x29,
++ LIS302DL_REG_OUT_Y = 0x2b,
++ LIS302DL_REG_OUT_Z = 0x2d,
++ LIS302DL_REG_FF_WU_CFG_1 = 0x30,
++ LIS302DL_REG_FF_WU_SRC_1 = 0x31,
++ LIS302DL_REG_FF_WU_THS_1 = 0x32,
++ LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
++ LIS302DL_REG_FF_WU_CFG_2 = 0x34,
++ LIS302DL_REG_FF_WU_SRC_2 = 0x35,
++ LIS302DL_REG_FF_WU_THS_2 = 0x36,
++ LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
++ LIS302DL_REG_CLICK_CFG = 0x38,
++ LIS302DL_REG_CLICK_SRC = 0x39,
++ LIS302DL_REG_CLICK_THSY_X = 0x3b,
++ LIS302DL_REG_CLICK_THSZ = 0x3c,
++ LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
++ LIS302DL_REG_CLICK_LATENCY = 0x3e,
++ LIS302DL_REG_CLICK_WINDOW = 0x3f,
++};
++
++enum lis302dl_reg_ctrl1 {
++ LIS302DL_CTRL1_Xen = 0x01,
++ LIS302DL_CTRL1_Yen = 0x02,
++ LIS302DL_CTRL1_Zen = 0x04,
++ LIS302DL_CTRL1_STM = 0x08,
++ LIS302DL_CTRL1_STP = 0x10,
++ LIS302DL_CTRL1_FS = 0x20,
++ LIS302DL_CTRL1_PD = 0x40,
++ LIS302DL_CTRL1_DR = 0x80,
++};
++
++enum lis302dl_reg_ctrl3 {
++ LIS302DL_CTRL3_PP_OD = 0x40,
++};
++
++enum lis302dl_reg_status {
++ LIS302DL_STATUS_XDA = 0x01,
++ LIS302DL_STATUS_YDA = 0x02,
++ LIS302DL_STATUS_ZDA = 0x04,
++ LIS302DL_STATUS_XYZDA = 0x08,
++ LIS302DL_STATUS_XOR = 0x10,
++ LIS302DL_STATUS_YOR = 0x20,
++ LIS302DL_STATUS_ZOR = 0x40,
++ LIS302DL_STATUS_XYZOR = 0x80,
++};
++
++enum lis302dl_reg_ffwusrc1 {
++ LIS302DL_FFWUSRC1_XL = 0x01,
++ LIS302DL_FFWUSRC1_XH = 0x02,
++ LIS302DL_FFWUSRC1_YL = 0x04,
++ LIS302DL_FFWUSRC1_YH = 0x08,
++ LIS302DL_FFWUSRC1_ZL = 0x10,
++ LIS302DL_FFWUSRC1_ZH = 0x20,
++ LIS302DL_FFWUSRC1_IA = 0x40,
++};
++
++enum lis302dl_reg_cloik_src {
++ LIS302DL_CLICKSRC_SINGLE_X = 0x01,
++ LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
++ LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
++ LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
++ LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
++ LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
++ LIS302DL_CLICKSRC_IA = 0x40,
++};
++
++struct lis302dl_info {
++ struct spi_device *spi_dev;
++ struct input_dev *input_dev;
++ struct mutex lock;
++ struct work_struct work;
++ unsigned int flags;
++ unsigned int working;
++ u_int8_t regs[0x40];
++};
++
++#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */
++#define LIS302DL_F_WUP_CLICK 0x0002
++#define LIS302DL_F_POWER 0x0010
++#define LIS302DL_F_FS 0x0020 /* ADC full scale */
++
++/* lowlevel register access functions */
++
++#define READ_BIT 0x01
++#define MS_BIT 0x02
++#define ADDR_SHIFT 2
++
++static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
++{
++ int rc;
++ u_int8_t cmd;
++
++ cmd = (reg << ADDR_SHIFT) | READ_BIT;
++
++ rc = spi_w8r8(lis->spi_dev, cmd);
++
++ return rc;
++}
++
++static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
++{
++ u_int8_t ret;
++
++ mutex_lock(&lis->lock);
++ ret = __reg_read(lis, reg);
++ mutex_unlock(&lis->lock);
++
++ return ret;
++}
++
++static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
++{
++ u_int8_t buf[2];
++
++ buf[0] = (reg << ADDR_SHIFT);
++ buf[1] = val;
++
++ return spi_write(lis->spi_dev, buf, sizeof(buf));
++}
++
++static int reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
++{
++ int ret;
++
++ mutex_lock(&lis->lock);
++ ret = __reg_write(lis, reg, val);
++ mutex_unlock(&lis->lock);
++
++ return ret;
++}
++
++static int reg_set_bit_mask(struct lis302dl_info *lis,
++ u_int8_t reg, u_int8_t mask, u_int8_t val)
++{
++ int ret;
++ u_int8_t tmp;
++
++ val &= mask;
++
++ mutex_lock(&lis->lock);
++
++ tmp = __reg_read(lis, reg);
++ tmp &= ~mask;
++ tmp |= val;
++ ret = __reg_write(lis, reg, tmp);
++
++ mutex_unlock(&lis->lock);
++
++ return ret;
++}
++
++/* interrupt handling related */
++
++enum lis302dl_intmode {
++ LIS302DL_INTMODE_GND = 0x00,
++ LIS302DL_INTMODE_FF_WU_1 = 0x01,
++ LIX302DL_INTMODE_FF_WU_2 = 0x02,
++ LIX302DL_INTMODE_FF_WU_12 = 0x03,
++ LIX302DL_INTMODE_DATA_READY = 0x04,
++ LIX302DL_INTMODE_CLICK = 0x07,
++};
++
++static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
++ enum lis302dl_intmode mode)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++
++ if (int_pin == 1)
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
++ else if (int_pin == 2)
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
++}
++
++static void _report_btn_single(struct input_dev *inp, int btn)
++{
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++}
++
++static void _report_btn_double(struct input_dev *inp, int btn)
++{
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++ input_sync(inp);
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++}
++
++static void lis302dl_work(struct work_struct *work)
++{
++ struct lis302dl_info *lis =
++ container_of(work, struct lis302dl_info, work);
++
++ u_int8_t status, ff_wu_src_1, click_src;
++ u_int8_t val;
++
++ lis->working = 1;
++
++ status = reg_read(lis, LIS302DL_REG_STATUS);
++ ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
++ click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
++
++ if (status & LIS302DL_STATUS_XDA) {
++ val = reg_read(lis, LIS302DL_REG_OUT_X);
++ if (lis->flags & LIS302DL_F_FS)
++ val = val << 2;
++ input_report_rel(lis->input_dev, REL_X, val);
++ }
++
++ if (status & LIS302DL_STATUS_YDA) {
++ val = reg_read(lis, LIS302DL_REG_OUT_Y);
++ if (lis->flags & LIS302DL_F_FS)
++ val = val << 2;
++ input_report_rel(lis->input_dev, REL_Y, val);
++ }
++
++ if (status & LIS302DL_STATUS_ZDA) {
++ val = reg_read(lis, LIS302DL_REG_OUT_Z);
++ if (lis->flags & LIS302DL_F_FS)
++ val = val << 2;
++ input_report_rel(lis->input_dev, REL_Z, val);
++ }
++
++ if (status & 0xf0)
++ dev_dbg(&lis->spi_dev->dev, "overrun!\n");
++
++ /* FIXME: implement overrun statistics */
++
++ if (ff_wu_src_1 & LIS302DL_FFWUSRC1_IA) {
++ /* FIXME: free fall interrupt handling */
++ }
++
++ if (click_src & LIS302DL_CLICKSRC_IA) {
++ if (click_src & LIS302DL_CLICKSRC_SINGLE_X)
++ _report_btn_single(lis->input_dev, BTN_X);
++ if (click_src & LIS302DL_CLICKSRC_DOUBLE_X)
++ _report_btn_double(lis->input_dev, BTN_X);
++
++ if (click_src & LIS302DL_CLICKSRC_SINGLE_Y)
++ _report_btn_single(lis->input_dev, BTN_Y);
++ if (click_src & LIS302DL_CLICKSRC_DOUBLE_Y)
++ _report_btn_double(lis->input_dev, BTN_Y);
++
++ if (click_src & LIS302DL_CLICKSRC_SINGLE_Z)
++ _report_btn_single(lis->input_dev, BTN_Z);
++ if (click_src & LIS302DL_CLICKSRC_DOUBLE_Z)
++ _report_btn_double(lis->input_dev, BTN_Z);
++ }
++
++ lis->working = 0;
++ input_sync(lis->input_dev);
++ put_device(&lis->spi_dev->dev);
++
++ enable_irq(lis->spi_dev->irq);
++}
++
++static void lis302dl_schedule_work(struct lis302dl_info *lis)
++{
++ int status;
++
++ get_device(&lis->spi_dev->dev);
++ status = schedule_work(&lis->work);
++ if (!status && !lis->working)
++ dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
++}
++
++static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
++{
++ struct lis302dl_info *lis = _lis;
++
++ lis302dl_schedule_work(lis);
++
++ /* Disable any further interrupts until we have processed
++ * the current one */
++ disable_irq(lis->spi_dev->irq);
++
++ return IRQ_HANDLED;
++}
++
++/* sysfs */
++
++static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
++
++ return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
++}
++
++static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ if (!strcmp(buf, "400\n"))
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
++ LIS302DL_CTRL1_DR);
++ else
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, 0);
++
++ return count;
++}
++
++static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
++
++static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
++
++ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
++}
++
++static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ if (!strcmp(buf, "9.2\n"))
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
++ LIS302DL_CTRL1_FS);
++ else
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, 0);
++
++ return count;
++}
++
++static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
++
++static struct attribute *lis302dl_sysfs_entries[] = {
++ &dev_attr_sample_rate.attr,
++ &dev_attr_full_scale.attr,
++};
++
++static struct attribute_group lis302dl_attr_group = {
++ .name = NULL,
++ .attrs = lis302dl_sysfs_entries,
++};
++
++/* input device handling and driver core interaction */
++
++static int lis302dl_input_open(struct input_dev *inp)
++{
++ struct lis302dl_info *lis = inp->private;
++ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
++
++ /* make sure we're powered up and generate data ready */
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
++
++ return 0;
++}
++
++static void lis302dl_input_close(struct input_dev *inp)
++{
++ struct lis302dl_info *lis = inp->private;
++ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
++ LIS302DL_CTRL1_Zen;
++
++ /* since the input core already serializes access and makes sure we
++ * only see close() for the close of the lastre user, we can safely
++ * disable the data ready events */
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
++
++ /* however, don't power down the whole device if still needed */
++ if (!(lis->flags & LIS302DL_F_WUP_FF ||
++ lis->flags & LIS302DL_F_WUP_CLICK)) {
++ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
++ 0x00);
++ }
++}
++
++static int __devinit lis302dl_probe(struct spi_device *spi)
++{
++ int rc;
++ struct lis302dl_info *lis;
++ u_int8_t wai;
++
++ lis = kzalloc(sizeof(*lis), GFP_KERNEL);
++ if (!lis)
++ return -ENOMEM;
++
++ mutex_init(&lis->lock);
++ INIT_WORK(&lis->work, lis302dl_work);
++ lis->spi_dev = spi;
++
++ spi_set_drvdata(spi, lis);
++
++ rc = spi_setup(spi);
++ if (rc < 0) {
++ printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(lis);
++ return rc;
++ }
++
++ wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
++ if (wai != LIS302DL_WHO_AM_I_MAGIC) {
++ printk(KERN_ERR "unknown who_am_i signature 0x%02x\n", wai);
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(lis);
++ return -ENODEV;
++ }
++
++ /* switch interrupt to open collector */
++ reg_write(lis, LIS302DL_CTRL3_PP_OD, 0x7c);
++
++ rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt, IRQF_DISABLED,
++ "lis302dl", NULL);
++ if (rc < 0) {
++ dev_err(&spi->dev, "error requesting IRQ %d\n",
++ lis->spi_dev->irq);
++ /* FIXME */
++ return rc;
++ }
++
++ rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
++ if (rc) {
++ dev_err(&spi->dev, "error creating sysfs group\n");
++ /* FIXME */
++ return rc;
++ }
++
++ /* initialize input layer details */
++ lis->input_dev = input_allocate_device();
++ if (!lis->input_dev) {
++ dev_err(&spi->dev, "Unable to allocate input device\n");
++ /* FIXME */
++ }
++
++ set_bit(EV_REL, lis->input_dev->evbit);
++ set_bit(EV_KEY, lis->input_dev->evbit);
++ set_bit(BTN_X, lis->input_dev->keybit);
++ set_bit(BTN_Y, lis->input_dev->keybit);
++ set_bit(BTN_Z, lis->input_dev->keybit);
++
++ lis->input_dev->private = lis;
++ lis->input_dev->name = "lis302dl"; /* FIXME: platform data */
++ lis->input_dev->id.bustype = BUS_I2C; /* FIXME: SPI Bus */
++ lis->input_dev->open = lis302dl_input_open;
++ lis->input_dev->close = lis302dl_input_close;
++
++ input_register_device(lis->input_dev);
++
++ return 0;
++}
++
++static int __devexit lis302dl_remove(struct spi_device *spi)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++
++ /* power down the device */
++ reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
++ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
++ input_unregister_device(lis->input_dev);
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(lis);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++
++ /* save registers */
++ lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
++ lis->regs[LIS302DL_REG_CTRL2] = reg_read(lis, LIS302DL_REG_CTRL2);
++ lis->regs[LIS302DL_REG_CTRL3] = reg_read(lis, LIS302DL_REG_CTRL3);
++ lis->regs[LIS302DL_REG_FF_WU_CFG_1] =
++ reg_read(lis, LIS302DL_REG_FF_WU_CFG_1);
++ lis->regs[LIS302DL_REG_FF_WU_THS_1] =
++ reg_read(lis, LIS302DL_REG_FF_WU_THS_1);
++ lis->regs[LIS302DL_REG_FF_WU_DURATION_1] =
++ reg_read(lis, LIS302DL_REG_FF_WU_DURATION_1);
++ lis->regs[LIS302DL_REG_FF_WU_CFG_2] =
++ reg_read(lis, LIS302DL_REG_FF_WU_CFG_2);
++ lis->regs[LIS302DL_REG_FF_WU_THS_2] =
++ reg_read(lis, LIS302DL_REG_FF_WU_THS_2);
++ lis->regs[LIS302DL_REG_FF_WU_DURATION_2] =
++ reg_read(lis, LIS302DL_REG_FF_WU_DURATION_2);
++ lis->regs[LIS302DL_REG_CLICK_CFG] =
++ reg_read(lis, LIS302DL_REG_CLICK_CFG);
++ lis->regs[LIS302DL_REG_CLICK_THSY_X] =
++ reg_read(lis, LIS302DL_REG_CLICK_THSY_X);
++ lis->regs[LIS302DL_REG_CLICK_THSZ] =
++ reg_read(lis, LIS302DL_REG_CLICK_THSZ);
++ lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT] =
++ reg_read(lis, LIS302DL_REG_CLICK_TIME_LIMIT);
++ lis->regs[LIS302DL_REG_CLICK_LATENCY] =
++ reg_read(lis, LIS302DL_REG_CLICK_LATENCY);
++ lis->regs[LIS302DL_REG_CLICK_WINDOW] =
++ reg_read(lis, LIS302DL_REG_CLICK_WINDOW);
++
++ /* determine if we want to wake up from the accel. */
++ if (!(lis->flags & LIS302DL_F_WUP_FF ||
++ lis->flags & LIS302DL_F_WUP_CLICK)) {
++ /* power down */
++ u_int8_t tmp;
++ tmp = reg_read(lis, LIS302DL_REG_CTRL1);
++ tmp &= ~LIS302DL_CTRL1_PD;
++ reg_write(lis, LIS302DL_REG_CTRL1, tmp);
++ }
++
++ return 0;
++}
++
++static int lis302dl_resume(struct spi_device *spi)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++
++ /* restore registers after resume */
++ reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
++ reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
++ reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
++ reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
++ lis->regs[LIS302DL_REG_FF_WU_CFG_1]);
++ reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
++ lis->regs[LIS302DL_REG_FF_WU_THS_1]);
++ reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ lis->regs[LIS302DL_REG_FF_WU_DURATION_1]);
++ reg_write(lis, LIS302DL_REG_FF_WU_CFG_2,
++ lis->regs[LIS302DL_REG_FF_WU_CFG_2]);
++ reg_write(lis, LIS302DL_REG_FF_WU_THS_2,
++ lis->regs[LIS302DL_REG_FF_WU_THS_2]);
++ reg_write(lis, LIS302DL_REG_FF_WU_DURATION_2,
++ lis->regs[LIS302DL_REG_FF_WU_DURATION_2]);
++ reg_write(lis, LIS302DL_REG_CLICK_CFG,
++ lis->regs[LIS302DL_REG_CLICK_CFG]);
++ reg_write(lis, LIS302DL_REG_CLICK_THSY_X,
++ lis->regs[LIS302DL_REG_CLICK_THSY_X]);
++ reg_write(lis, LIS302DL_REG_CLICK_THSZ,
++ lis->regs[LIS302DL_REG_CLICK_THSZ]);
++ reg_write(lis, LIS302DL_REG_CLICK_TIME_LIMIT,
++ lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT]);
++ reg_write(lis, LIS302DL_REG_CLICK_LATENCY,
++ lis->regs[LIS302DL_REG_CLICK_LATENCY]);
++ reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
++ lis->regs[LIS302DL_REG_CLICK_WINDOW]);
++
++ return 0;
++}
++#else
++#define lis302dl_suspend NULL
++#define lis302dl_resume NULL
++#endif
++
++static struct spi_driver lis302dl_driver = {
++ .driver = {
++ .name = "lis302dl",
++ .owner = THIS_MODULE,
++ },
++
++ .probe = lis302dl_probe,
++ .remove = __devexit_p(lis302dl_remove),
++ .suspend = lis302dl_suspend,
++ .resume = lis302dl_resume,
++};
++
++static int __init lis302dl_init(void)
++{
++ return spi_register_driver(&lis302dl_driver);
++}
++
++static void __exit lis302dl_exit(void)
++{
++ spi_unregister_driver(&lis302dl_driver);
++}
++
++MODULE_AUTHOR("Harald Welte <laforge at openmoko.org>");
++MODULE_LICENSE("GPL");
++
++module_init(lis302dl_init);
++module_exit(lis302dl_exit);
+Index: linux-2.6.22.5-moko/drivers/spi/Kconfig
+===================================================================
+--- linux-2.6.22.5-moko.orig/drivers/spi/Kconfig
++++ linux-2.6.22.5-moko/drivers/spi/Kconfig
+@@ -197,5 +197,9 @@
+ tristate "tpo JP6K74 LCM ASIC"
+ depends on SPI_MASTER && (MACH_NEO1973_GTA01 || MACH_QT2410)
+
++config SPI_SLAVE_LIS302DL
++ tristate "STmicro LIS302DL 3-axis accelerometer"
++ depends on SPI_MASTER && MACH_NEO1973_GTA02
++
+ endmenu # "SPI support"
+
+Index: linux-2.6.22.5-moko/drivers/spi/Makefile
+===================================================================
+--- linux-2.6.22.5-moko.orig/drivers/spi/Makefile
++++ linux-2.6.22.5-moko/drivers/spi/Makefile
+@@ -35,4 +35,5 @@
+
+ # SPI slave drivers (protocol for that link)
+ obj-$(CONFIG_SPI_SLAVE_JBT6K74) += jbt6k74.o
++obj-$(CONFIG_SPI_SLAVE_LIS302DL) += lis302dl.o
+ # ... add above this line ...
+Index: linux-2.6.22.5-moko/include/linux/lis302dl.h
+===================================================================
+--- /dev/null
++++ linux-2.6.22.5-moko/include/linux/lis302dl.h
+@@ -0,0 +1,11 @@
++#ifndef _LINUX_LIS302DL_H
++#define _LINUX_LIS302DL_H
++
++#include <linux/types.h>
++
++struct lis302dl_platform_data {
++ char *name;
++};
++
++#endif /* _LINUX_LIS302DL_H */
++
Modified: branches/src/target/kernel/2.6.23.x/patches/series
===================================================================
--- branches/src/target/kernel/2.6.23.x/patches/series 2007-10-09 14:12:02 UTC (rev 3124)
+++ branches/src/target/kernel/2.6.23.x/patches/series 2007-10-09 15:10:29 UTC (rev 3125)
@@ -46,3 +46,4 @@
explicitly-link-notes-section.patch
fix-s3c2410fb-register-access.patch
gta-vibrator.patch
+lis302dl.patch
More information about the commitlog
mailing list