summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Jansa <Martin.Jansa@gmail.com>2010-05-19 18:53:47 +0200
committerMartin Jansa <Martin.Jansa@gmail.com>2010-05-25 09:09:24 +0200
commitedc90bdfa987ddc140c72891de4b41ae0bb2ef04 (patch)
treec0c44d7e3c7fb947a61b6e54eb8c0bab185be964
parenta9102cac0e6f56766e7317d9ea7af357a1593af7 (diff)
linux-openmoko-2.6.34: add rebased gdrm and qtmoko patches, use gta02_drm_defconfig again
Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch458
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch1759
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0002-Glamo-DRM-and-KMS-driver.patch3869
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0002-usbhost.patch.patch414
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0003-Work-on-Glamo-core-for-DRM.patch162
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0003-ar6000_delay.patch.patch29
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch540
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0004-save_regs.patch.patch140
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0005-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch38
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0006-Fix-dynamic-command-queue-allocation.patch131
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0007-Debug-statements-for-testing.patch78
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0008-Fix-claim-of-2D-register-resource.patch27
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0009-Use-unlocked_ioctl-rather-than-ioctl.patch28
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/gta02-defconfig-update-for-2.6.34.patch880
-rw-r--r--recipes/linux/linux-openmoko-2.6.34_git.bb23
15 files changed, 7691 insertions, 885 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch b/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch
new file mode 100644
index 0000000000..56197a263f
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch
@@ -0,0 +1,458 @@
+From 69d87612a1b545e6d4cf9fc93117be86f871f7d2 Mon Sep 17 00:00:00 2001
+From: Thomas White <taw@bitwiz.org.uk>
+Date: Sat, 22 May 2010 18:59:58 +0200
+Subject: [PATCH 01/13] DRM for platform devices
+
+This modifies the DRM core in a small number of places to allow platform
+devices to be used for direct rendering, alongside PCI devices.
+
+Signed-off-by: Thomas White <taw@bitwiz.org.uk>
+---
+ drivers/gpu/drm/Kconfig | 2 +-
+ drivers/gpu/drm/drm_bufs.c | 2 +-
+ drivers/gpu/drm/drm_drv.c | 27 ++++++++++
+ drivers/gpu/drm/drm_info.c | 27 ++++++++--
+ drivers/gpu/drm/drm_ioctl.c | 118 ++++++++++++++++++++++++++++++-------------
+ drivers/gpu/drm/drm_stub.c | 76 +++++++++++++++++++++++++++-
+ drivers/gpu/drm/drm_sysfs.c | 6 ++-
+ include/drm/drmP.h | 13 +++++
+ 8 files changed, 224 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
+index 305c590..7244cef 100644
+--- a/drivers/gpu/drm/Kconfig
++++ b/drivers/gpu/drm/Kconfig
+@@ -6,7 +6,7 @@
+ #
+ menuconfig DRM
+ tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
+- depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
++ depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
+ select I2C
+ select I2C_ALGOBIT
+ help
+diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
+index f7ba82e..30ce982 100644
+--- a/drivers/gpu/drm/drm_bufs.c
++++ b/drivers/gpu/drm/drm_bufs.c
+@@ -189,7 +189,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
++#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__)
+ if (map->offset + (map->size-1) < map->offset ||
+ map->offset < virt_to_phys(high_memory)) {
+ kfree(map);
+diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
+index 4a66201..769d12b 100644
+--- a/drivers/gpu/drm/drm_drv.c
++++ b/drivers/gpu/drm/drm_drv.c
+@@ -250,6 +250,7 @@ int drm_lastclose(struct drm_device * dev)
+ */
+ int drm_init(struct drm_driver *driver)
+ {
++#ifdef CONFIG_PCI
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *pid;
+ int i;
+@@ -283,11 +284,37 @@ int drm_init(struct drm_driver *driver)
+ drm_get_dev(pdev, pid, driver);
+ }
+ }
++#endif
+ return 0;
+ }
+
+ EXPORT_SYMBOL(drm_init);
+
++/**
++ * Call this to associate a drm_driver with a platform_device.
++ *
++ * \return zero on success or a negative number on failure.
++ *
++ * This is a replacement for drm_init(), but for platform drivers.
++ * In this case, the caller must provide the matching platform_device
++ *
++ * since there is no physical bus to scan through.
++ *
++ * \sa drm_init
++ *
++ */
++int drm_platform_init(struct drm_driver *driver, struct platform_device *pdev,
++ void *priv)
++{
++ DRM_DEBUG("\n");
++
++ INIT_LIST_HEAD(&driver->device_list);
++
++ return drm_get_platform_dev(pdev, driver, priv);
++}
++
++EXPORT_SYMBOL(drm_platform_init);
++
+ void drm_exit(struct drm_driver *driver)
+ {
+ struct drm_device *dev, *tmp;
+diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
+index f0f6c6b..838c2ee 100644
+--- a/drivers/gpu/drm/drm_info.c
++++ b/drivers/gpu/drm/drm_info.c
+@@ -52,12 +52,28 @@ int drm_name_info(struct seq_file *m, void *data)
+ return 0;
+
+ if (master->unique) {
+- seq_printf(m, "%s %s %s\n",
+- dev->driver->pci_driver.name,
+- pci_name(dev->pdev), master->unique);
++
++ if (drm_core_is_platform(dev)) {
++ seq_printf(m, "%s %s %s\n",
++ dev->driver->name,
++ dev_name(&dev->platform_dev->dev),
++ master->unique);
++ } else {
++ seq_printf(m, "%s %s %s\n",
++ dev->driver->pci_driver.name,
++ pci_name(dev->pdev), master->unique);
++ }
++
+ } else {
+- seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
+- pci_name(dev->pdev));
++
++ if (drm_core_is_platform(dev)) {
++ seq_printf(m, "%s %s\n", dev->driver->name,
++ dev_name(&dev->platform_dev->dev));
++ } else {
++ seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
++ pci_name(dev->pdev));
++ }
++
+ }
+
+ return 0;
+@@ -325,4 +341,3 @@ int drm_vma_info(struct seq_file *m, void *data)
+ }
+
+ #endif
+-
+diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
+index 9b9ff46..133ef29 100644
+--- a/drivers/gpu/drm/drm_ioctl.c
++++ b/drivers/gpu/drm/drm_ioctl.c
+@@ -83,7 +83,6 @@ int drm_setunique(struct drm_device *dev, void *data,
+ {
+ struct drm_unique *u = data;
+ struct drm_master *master = file_priv->master;
+- int domain, bus, slot, func, ret;
+
+ if (master->unique_len || master->unique)
+ return -EBUSY;
+@@ -101,28 +100,46 @@ int drm_setunique(struct drm_device *dev, void *data,
+
+ master->unique[master->unique_len] = '\0';
+
+- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
+- strlen(master->unique) + 2, GFP_KERNEL);
+- if (!dev->devname)
+- return -ENOMEM;
++ if ( !drm_core_is_platform(dev) ) {
+
+- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+- master->unique);
++ int domain, bus, slot, func, ret;
+
+- /* Return error if the busid submitted doesn't match the device's actual
+- * busid.
+- */
+- ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+- if (ret != 3)
+- return -EINVAL;
+- domain = bus >> 8;
+- bus &= 0xff;
++ /* PCI device */
++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
++ strlen(master->unique) + 2, GFP_KERNEL);
++ if (!dev->devname)
++ return -ENOMEM;
+
+- if ((domain != drm_get_pci_domain(dev)) ||
+- (bus != dev->pdev->bus->number) ||
+- (slot != PCI_SLOT(dev->pdev->devfn)) ||
+- (func != PCI_FUNC(dev->pdev->devfn)))
+- return -EINVAL;
++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
++ master->unique);
++
++ /* Return error if the busid submitted doesn't match the
++ * device's actual busid.
++ */
++ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
++ if (ret != 3)
++ return -EINVAL;
++ domain = bus >> 8;
++ bus &= 0xff;
++
++ if ((domain != drm_get_pci_domain(dev)) ||
++ (bus != dev->pdev->bus->number) ||
++ (slot != PCI_SLOT(dev->pdev->devfn)) ||
++ (func != PCI_FUNC(dev->pdev->devfn)))
++ return -EINVAL;
++
++ } else {
++
++ /* Platform device */
++ dev->devname = kmalloc(strlen(dev->driver->name) +
++ strlen(master->unique) + 2, GFP_KERNEL);
++ if (!dev->devname)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->name,
++ master->unique);
++
++ }
+
+ return 0;
+ }
+@@ -141,23 +158,52 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+- len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
+- drm_get_pci_domain(dev),
+- dev->pdev->bus->number,
+- PCI_SLOT(dev->pdev->devfn),
+- PCI_FUNC(dev->pdev->devfn));
+- if (len >= master->unique_len)
+- DRM_ERROR("buffer overflow");
+- else
+- master->unique_len = len;
+-
+- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
+- master->unique_len + 2, GFP_KERNEL);
+- if (dev->devname == NULL)
+- return -ENOMEM;
++ if ( !drm_core_is_platform(dev) ) {
++
++ /* PCI device */
+
+- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+- master->unique);
++ len = snprintf(master->unique, master->unique_len,
++ "pci:%04x:%02x:%02x.%d",
++ drm_get_pci_domain(dev),
++ dev->pdev->bus->number,
++ PCI_SLOT(dev->pdev->devfn),
++ PCI_FUNC(dev->pdev->devfn));
++ if (len >= master->unique_len)
++ DRM_ERROR("buffer overflow");
++ else
++ master->unique_len = len;
++
++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
++ master->unique_len + 2, GFP_KERNEL);
++ if (dev->devname == NULL)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
++ master->unique);
++
++ } else {
++
++ /* Platform device */
++
++ int len;
++
++ len = snprintf(master->unique, master->unique_len,
++ "platform:%s", dev->platform_dev->name);
++
++ if (len >= master->unique_len)
++ DRM_ERROR("buffer overflow");
++ else
++ master->unique_len = len;
++
++ dev->devname = kmalloc(strlen(dev->driver->name)
++ + master->unique_len + 2, GFP_KERNEL);
++ if (dev->devname == NULL)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->name,
++ master->unique);
++
++ }
+
+ return 0;
+ }
+diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
+index a0c365f..7e7eba6 100644
+--- a/drivers/gpu/drm/drm_stub.c
++++ b/drivers/gpu/drm/drm_stub.c
+@@ -246,8 +246,10 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
+ idr_init(&dev->drw_idr);
+
+ dev->pdev = pdev;
+- dev->pci_device = pdev->device;
+- dev->pci_vendor = pdev->vendor;
++ if (pdev) {
++ dev->pci_device = pdev->device;
++ dev->pci_vendor = pdev->vendor;
++ }
+
+ #ifdef __alpha__
+ dev->hose = pdev->sysdata;
+@@ -465,6 +467,76 @@ err_g1:
+ EXPORT_SYMBOL(drm_get_dev);
+
+ /**
++ *
++ * Register a platform device as a DRM device
++ *
++ * \param pdev - platform device structure
++ * \param driver - the matching drm_driver structure
++ * \return zero on success or a negative number on failure.
++ *
++ * Attempt to gets inter module "drm" information. If we are first
++ * then register the character device and inter module information.
++ * Try and register, if we fail to register, backout previous work.
++ *
++ * \sa drm_get_dev
++ */
++int drm_get_platform_dev(struct platform_device *pdev,
++ struct drm_driver *driver, void *priv)
++{
++ struct drm_device *dev;
++ int ret;
++ DRM_DEBUG("\n");
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++ dev->dev_private = priv;
++
++ if ((ret = drm_fill_in_dev(dev, NULL, NULL, driver))) {
++ printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
++ goto err_g1;
++ }
++ dev->platform_dev = pdev;
++
++ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
++ ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
++ if (ret)
++ goto err_g2;
++ }
++
++ if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
++ goto err_g3;
++
++ if (dev->driver->load) {
++ ret = dev->driver->load(dev, 0);
++ if (ret)
++ goto err_g3;
++ }
++
++ /* setup the grouping for the legacy output */
++ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
++ ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
++ if (ret)
++ goto err_g3;
++ }
++
++ list_add_tail(&dev->driver_item, &driver->device_list);
++
++ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
++ driver->name, driver->major, driver->minor, driver->patchlevel,
++ driver->date, dev->primary->index);
++
++ return 0;
++
++err_g3:
++ drm_put_minor(&dev->primary);
++err_g2:
++err_g1:
++ kfree(dev);
++ return ret;
++}
++
++/**
+ * Put a secondary minor number.
+ *
+ * \param sec_minor - structure to be released
+diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
+index 25bbd30..947e731 100644
+--- a/drivers/gpu/drm/drm_sysfs.c
++++ b/drivers/gpu/drm/drm_sysfs.c
+@@ -488,7 +488,11 @@ int drm_sysfs_device_add(struct drm_minor *minor)
+ int err;
+ char *minor_str;
+
+- minor->kdev.parent = &minor->dev->pdev->dev;
++ if (minor->dev->pdev) {
++ minor->kdev.parent = &minor->dev->pdev->dev;
++ } else {
++ minor->kdev.parent = &minor->dev->platform_dev->dev;
++ }
+ minor->kdev.class = drm_class;
+ minor->kdev.release = drm_sysfs_device_release;
+ minor->kdev.devt = minor->device;
+diff --git a/include/drm/drmP.h b/include/drm/drmP.h
+index 2f3b3a0..43894ec 100644
+--- a/include/drm/drmP.h
++++ b/include/drm/drmP.h
+@@ -56,6 +56,7 @@
+ #include <linux/cdev.h>
+ #include <linux/mutex.h>
+ #include <linux/slab.h>
++#include <linux/platform_device.h>
+ #if defined(__alpha__) || defined(__powerpc__)
+ #include <asm/pgtable.h> /* For pte_wrprotect */
+ #endif
+@@ -144,6 +145,7 @@ extern void drm_ut_debug_printk(unsigned int request_level,
+ #define DRIVER_IRQ_VBL2 0x800
+ #define DRIVER_GEM 0x1000
+ #define DRIVER_MODESET 0x2000
++#define DRIVER_IS_PLATFORM 0x4000
+
+ /***********************************************************************/
+ /** \name Begin the DRM... */
+@@ -1014,6 +1016,7 @@ struct drm_device {
+ wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */
+
+ struct drm_agp_head *agp; /**< AGP data */
++ struct platform_device *platform_dev; /**< platform device structure */
+
+ struct pci_dev *pdev; /**< PCI device structure */
+ int pci_vendor; /**< PCI vendor id */
+@@ -1124,12 +1127,20 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
+ }
+ #endif
+
++static inline int drm_core_is_platform(struct drm_device *dev)
++{
++ return drm_core_check_feature(dev, DRIVER_IS_PLATFORM);
++}
++
+ /******************************************************************/
+ /** \name Internal function definitions */
+ /*@{*/
+
+ /* Driver support (drm_drv.h) */
+ extern int drm_init(struct drm_driver *driver);
++extern int drm_platform_init(struct drm_driver *driver,
++ struct platform_device *pdev,
++ void *dev_private);
+ extern void drm_exit(struct drm_driver *driver);
+ extern long drm_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg);
+@@ -1350,6 +1361,8 @@ extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+ struct drm_master *drm_master_create(struct drm_minor *minor);
+ extern struct drm_master *drm_master_get(struct drm_master *master);
++extern int drm_get_platform_dev(struct platform_device *pdev,
++ struct drm_driver *driver, void *priv);
+ extern void drm_master_put(struct drm_master **master);
+ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver);
+--
+1.7.1
+
diff --git a/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch
new file mode 100644
index 0000000000..1b6964aee9
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch
@@ -0,0 +1,1759 @@
+From b4c5d1702abcaef7d8af5d3dc8934b2184ba6be0 Mon Sep 17 00:00:00 2001
+From: Radek Polak <psonek2@seznam.cz>
+Date: Fri, 9 Apr 2010 09:15:40 +0200
+Subject: [PATCH 1/4] accels.patch
+
+adds support for accelerometers. You will need include/linux/lis302dl.h and
+drivers/input/misc/lis302dl.c from andy-tracking. The patch needs
+spi_bitbang_transfer_sync() and bitbang_work() to be ported correctly (some
+fixes from original 2.6.32 are missing).
+
+Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
+---
+ arch/arm/mach-s3c2410/include/mach/spi-gpio.h | 3 +-
+ arch/arm/mach-s3c2440/mach-gta02.c | 157 ++++
+ drivers/input/misc/Kconfig | 9 +
+ drivers/input/misc/Makefile | 1 +
+ drivers/input/misc/lis302dl.c | 952 +++++++++++++++++++++++++
+ drivers/spi/spi_bitbang.c | 231 ++++---
+ drivers/spi/spi_s3c24xx_gpio.c | 7 +-
+ include/linux/lis302dl.h | 152 ++++
+ include/linux/spi/spi.h | 30 +
+ include/linux/spi/spi_bitbang.h | 5 +
+ 10 files changed, 1433 insertions(+), 114 deletions(-)
+ create mode 100644 drivers/input/misc/lis302dl.c
+ create mode 100644 include/linux/lis302dl.h
+
+diff --git a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+index dcef228..8eedc9c 100644
+--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
++++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+@@ -21,7 +21,8 @@ struct s3c2410_spigpio_info {
+ int num_chipselect;
+ int bus_num;
+
+- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
++ int non_blocking_transfer;
++ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs);
+ };
+
+
+diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
+index e8ac76b..795b9f4 100644
+--- a/arch/arm/mach-s3c2440/mach-gta02.c
++++ b/arch/arm/mach-s3c2440/mach-gta02.c
+@@ -62,6 +62,7 @@
+
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
++#include <linux/lis302dl.h>
+
+ #include <linux/leds.h>
+ #include <linux/leds_pwm.h>
+@@ -111,6 +112,22 @@
+ #include <linux/glamofb.h>
+ #include <linux/mfd/glamo.h>
+
++#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
++
++#define S3C2410_GPIO_BANKD (32*3)
++#define S3C2410_GPIO_BANKG (32*6)
++
++#define S3C2410_GPG5 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5)
++#define S3C2410_GPG6 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6)
++#define S3C2410_GPG7 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 7)
++#define S3C2410_GPD12 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 12)
++#define S3C2410_GPD13 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 13)
++
++#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
++#define BITBANG_CS_INACTIVE 0
++
++#define S3C_SYSTEM_REV_ATAG GTA02v6_SYSTEM_REV
++
+ static struct pcf50633 *gta02_pcf;
+
+ /*
+@@ -322,6 +339,60 @@ const static struct jbt6k74_platform_data jbt6k74_pdata = {
+ .gpio_reset = GTA02_GPIO_GLAMO(4),
+ };
+
++/*----------- SPI: Accelerometers attached to SPI of s3c244x ----------------- */
++
++void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
++{
++ struct lis302dl_platform_data *pdata = lis->pdata;
++
++ if (!resume) {
++ /*
++ * we don't want to power them with a high level
++ * because GSENSOR_3V3 is not up during suspend
++ */
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ s3c2410_gpio_setpin(pdata->pin_mosi, 0);
++ /* misnomer: it is a pullDOWN in 2442 */
++ s3c2410_gpio_pullup(pdata->pin_miso, 1);
++ return;
++ }
++
++ /* back to normal */
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ /* misnomer: it is a pullDOWN in 2442 */
++ s3c2410_gpio_pullup(pdata->pin_miso, 0);
++
++ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT);
++
++}
++
++struct lis302dl_platform_data lis302_pdata_top = {
++ .name = "lis302-1 (top)",
++ .pin_chip_select= S3C2410_GPD12,
++ .pin_clk = S3C2410_GPG7,
++ .pin_mosi = S3C2410_GPG6,
++ .pin_miso = S3C2410_GPG5,
++ .interrupt = GTA02_IRQ_GSENSOR_1,
++ .open_drain = 1, /* altered at runtime by PCB rev */
++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
++};
++
++struct lis302dl_platform_data lis302_pdata_bottom = {
++ .name = "lis302-2 (bottom)",
++ .pin_chip_select= S3C2410_GPD13,
++ .pin_clk = S3C2410_GPG7,
++ .pin_mosi = S3C2410_GPG6,
++ .pin_miso = S3C2410_GPG5,
++ .interrupt = GTA02_IRQ_GSENSOR_2,
++ .open_drain = 1, /* altered at runtime by PCB rev */
++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
++};
++
+ static struct spi_board_info gta02_spi_board_info[] = {
+ {
+ .modalias = "jbt6k74",
+@@ -332,6 +403,81 @@ static struct spi_board_info gta02_spi_board_info[] = {
+ .bus_num = 2,
+ .chip_select = 0
+ },
++ {
++ .modalias = "lis302dl",
++ /* platform_data */
++ .platform_data = &lis302_pdata_top,
++ /* controller_data */
++ /* irq */
++ .max_speed_hz = 100 * 1000,
++ .bus_num = 3,
++ .chip_select = 0,
++ },
++ {
++ .modalias = "lis302dl",
++ /* platform_data */
++ .platform_data = &lis302_pdata_bottom,
++ /* controller_data */
++ /* irq */
++ .max_speed_hz = 100 * 1000,
++ .bus_num = 3,
++ .chip_select = 1,
++ },
++};
++
++static void gta02_lis302_chip_select(struct s3c2410_spigpio_info *info, int csid, int cs)
++{
++
++ /*
++ * Huh... "quirk"... CS on this device is not really "CS" like you can
++ * expect.
++ *
++ * When it is 0 it selects SPI interface mode.
++ * When it is 1 it selects I2C interface mode.
++ *
++ * Because we have 2 devices on one interface we have to make sure
++ * that the "disabled" device (actually in I2C mode) don't think we're
++ * talking to it.
++ *
++ * When we talk to the "enabled" device, the "disabled" device sees
++ * the clocks as I2C clocks, creating havoc.
++ *
++ * I2C sees MOSI going LOW while CLK HIGH as a START action, thus we
++ * must ensure this is never issued.
++ */
++
++ int cs_gpio, other_cs_gpio;
++
++ cs_gpio = csid ? S3C2410_GPD13 : S3C2410_GPD12;
++ other_cs_gpio = (1 - csid) ? S3C2410_GPD13 : S3C2410_GPD12;
++
++
++ if (cs == BITBANG_CS_ACTIVE) {
++ s3c2410_gpio_setpin(other_cs_gpio, 1);
++ s3c2410_gpio_setpin(cs_gpio, 1);
++ s3c2410_gpio_setpin(info->pin_clk, 1);
++ s3c2410_gpio_setpin(cs_gpio, 0);
++ } else {
++ s3c2410_gpio_setpin(cs_gpio, 1);
++ s3c2410_gpio_setpin(other_cs_gpio, 1);
++ }
++}
++
++static struct s3c2410_spigpio_info gta02_spigpio_cfg = {
++ .pin_clk = S3C2410_GPG7,
++ .pin_mosi = S3C2410_GPG6,
++ .pin_miso = S3C2410_GPG5,
++ .bus_num = 3,
++ .num_chipselect = 2,
++ .chip_select = gta02_lis302_chip_select,
++ .non_blocking_transfer = 1,
++};
++
++static struct platform_device gta02_spi_gpio_dev = {
++ .name = "spi_s3c24xx_gpio",
++ .dev = {
++ .platform_data = &gta02_spigpio_cfg,
++ },
+ };
+
+ static struct resource gta02_glamo_resources[] = {
+@@ -1091,6 +1237,7 @@ static struct platform_device *gta02_devices[] __initdata = {
+ &gta02_pm_bt_dev,
+ &gta02_pm_wlan_dev,
+ &gta02_glamo_dev,
++ &gta02_spi_gpio_dev,
+ &s3c_device_adc,
+ &s3c_device_ts,
+ };
+@@ -1302,6 +1449,16 @@ static void __init gta02_machine_init(void)
+ /* Set the panic callback to make AUX LED blink at ~5Hz. */
+ panic_blink = gta02_panic_blink;
+
++ switch (S3C_SYSTEM_REV_ATAG) {
++ case GTA02v6_SYSTEM_REV:
++ /* we need push-pull interrupt from motion sensors */
++ lis302_pdata_top.open_drain = 0;
++ lis302_pdata_bottom.open_drain = 0;
++ break;
++ default:
++ break;
++ }
++
+ bus_register_notifier(&platform_bus_type, &gta02_device_register_notifier);
+ bus_register_notifier(&spi_bus_type, &gta02_device_register_notifier);
+
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index 23140a3..d8d0932 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -340,4 +340,13 @@ config INPUT_PCAP
+ To compile this driver as a module, choose M here: the
+ module will be called pcap_keys.
+
++config INPUT_LIS302DL
++ tristate "STmicro LIS302DL 3-axis accelerometer"
++ depends on SPI_MASTER
++ help
++ SPI driver for the STmicro LIS302DL 3-axis accelerometer.
++
++ The userspece interface is a 3-axis (X/Y/Z) relative movement
++ Linux input device, reporting REL_[XYZ] events.
++
+ endif
+diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
+index 7e95a5d..5b810db 100644
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -32,4 +32,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
+ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
+ obj-$(CONFIG_INPUT_YEALINK) += yealink.o
++obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
+
+diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
+new file mode 100644
+index 0000000..d345bfb
+--- /dev/null
++++ b/drivers/input/misc/lis302dl.c
+@@ -0,0 +1,952 @@
++/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
++ *
++ * Copyright (C) 2007-2008 by Openmoko, Inc.
++ * Author: Harald Welte <laforge@openmoko.org>
++ * converted to private bitbang by:
++ * Andy Green <andy@openmoko.com>
++ * ability to set acceleration threshold added by:
++ * Simon Kagstrom <simon.kagstrom@gmail.com>
++ * 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/irq.h>
++#include <linux/interrupt.h>
++#include <linux/sysfs.h>
++#include <linux/spi/spi.h>
++
++#include <linux/lis302dl.h>
++
++/* Utility functions */
++static u8 __reg_read(struct lis302dl_info *lis, u8 reg)
++{
++ struct spi_message msg;
++ struct spi_transfer t;
++ u8 data[2] = {0xc0 | reg};
++ int rc;
++
++ spi_message_init(&msg);
++ memset(&t, 0, sizeof t);
++ t.len = 2;
++ spi_message_add_tail(&t, &msg);
++ t.tx_buf = &data[0];
++ t.rx_buf = &data[0];
++
++ /* Should complete without blocking */
++ rc = spi_non_blocking_transfer(lis->spi, &msg);
++ if (rc < 0) {
++ dev_err(lis->dev, "Error reading register\n");
++ return rc;
++ }
++
++ return data[1];
++}
++
++static void __reg_write(struct lis302dl_info *lis, u8 reg, u8 val)
++{
++ struct spi_message msg;
++ struct spi_transfer t;
++ u8 data[2] = {reg, val};
++
++ spi_message_init(&msg);
++ memset(&t, 0, sizeof t);
++ t.len = 2;
++ spi_message_add_tail(&t, &msg);
++ t.tx_buf = &data[0];
++ t.rx_buf = &data[0];
++
++ /* Completes without blocking */
++ if (spi_non_blocking_transfer(lis->spi, &msg) < 0)
++ dev_err(lis->dev, "Error writing register\n");
++}
++
++static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
++ u8 val)
++{
++ u_int8_t tmp;
++
++ val &= mask;
++
++ tmp = __reg_read(lis, reg);
++ tmp &= ~mask;
++ tmp |= val;
++ __reg_write(lis, reg, tmp);
++}
++
++static int __ms_to_duration(struct lis302dl_info *lis, int ms)
++{
++ /* If we have 400 ms sampling rate, the stepping is 2.5 ms,
++ * on 100 ms the stepping is 10ms */
++ if (lis->flags & LIS302DL_F_DR)
++ return min((ms * 10) / 25, 637);
++
++ return min(ms / 10, 2550);
++}
++
++static int __duration_to_ms(struct lis302dl_info *lis, int duration)
++{
++ if (lis->flags & LIS302DL_F_DR)
++ return (duration * 25) / 10;
++
++ return duration * 10;
++}
++
++static u8 __mg_to_threshold(struct lis302dl_info *lis, int mg)
++{
++ /* If FS is set each bit is 71mg, otherwise 18mg. The THS register
++ * has 7 bits for the threshold value */
++ if (lis->flags & LIS302DL_F_FS)
++ return min(mg / 71, 127);
++
++ return min(mg / 18, 127);
++}
++
++static int __threshold_to_mg(struct lis302dl_info *lis, u8 threshold)
++{
++ if (lis->flags & LIS302DL_F_FS)
++ return threshold * 71;
++
++ return threshold * 18;
++}
++
++/* interrupt handling related */
++
++enum lis302dl_intmode {
++ LIS302DL_INTMODE_GND = 0x00,
++ LIS302DL_INTMODE_FF_WU_1 = 0x01,
++ LIS302DL_INTMODE_FF_WU_2 = 0x02,
++ LIS302DL_INTMODE_FF_WU_12 = 0x03,
++ LIS302DL_INTMODE_DATA_READY = 0x04,
++ LIS302DL_INTMODE_CLICK = 0x07,
++};
++
++static void __lis302dl_int_mode(struct device *dev, int int_pin,
++ enum lis302dl_intmode mode)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ switch (int_pin) {
++ case 1:
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
++ break;
++ case 2:
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
++ break;
++ default:
++ BUG();
++ }
++}
++
++static void __enable_wakeup(struct lis302dl_info *lis)
++{
++ __reg_write(lis, LIS302DL_REG_CTRL1, 0);
++
++ /* First zero to get to a known state */
++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
++ LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE |
++ LIS302DL_FFWUCFG_LIR);
++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
++ __mg_to_threshold(lis, lis->wakeup.threshold));
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ __ms_to_duration(lis, lis->wakeup.duration));
++
++ /* Route the interrupt for wakeup */
++ __lis302dl_int_mode(lis->dev, 1,
++ LIS302DL_INTMODE_FF_WU_1);
++
++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
++ __reg_read(lis, LIS302DL_REG_OUT_X);
++ __reg_read(lis, LIS302DL_REG_OUT_Y);
++ __reg_read(lis, LIS302DL_REG_OUT_Z);
++ __reg_read(lis, LIS302DL_REG_STATUS);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
++}
++
++static void __enable_data_collection(struct lis302dl_info *lis)
++{
++ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen