From 7c393dcee85c4ac5556f11a61300d01bbd9c037d Mon Sep 17 00:00:00 2001 From: Klaus Kurzmann Date: Mon, 17 May 2010 21:21:55 +0200 Subject: fsonetworkd_git.bb: add RDEPENDS for iptables Signed-off-by: Klaus Kurzmann --- recipes/freesmartphone/fsonetworkd_git.bb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/recipes/freesmartphone/fsonetworkd_git.bb b/recipes/freesmartphone/fsonetworkd_git.bb index e64de8e96d..974ac3ccc7 100644 --- a/recipes/freesmartphone/fsonetworkd_git.bb +++ b/recipes/freesmartphone/fsonetworkd_git.bb @@ -3,4 +3,5 @@ inherit fso-plugin SRCREV = "${FSO_CORNUCOPIA_SRCREV}" PV = "0.1.0.0+gitr${SRCPV}" PE = "1" -PR = "${INC_PR}.2" +PR = "${INC_PR}.3" +RDEPENDS += "iptables" -- cgit v1.2.3 From 14e1ed70361f7f5a5e54d93a606a7c8d53460b95 Mon Sep 17 00:00:00 2001 From: Martin Jansa Date: Mon, 17 May 2010 13:31:01 +0200 Subject: linux-openmoko-2.6.32: add patches from gdrm-for-merging instead of gdrm-2.6.32 branch and rebase Signed-off-by: Martin Jansa --- ...build-with-gcc-4.4.2-which-works-ok-with-.patch | 6 +- .../0002-DRM-for-platform-devices.patch | 458 --- .../linux-openmoko-2.6.32/0002-accels.patch.patch | 1759 +++++++++ .../0003-Glamo-DRM-and-KMS-driver.patch | 3788 ------------------- .../linux-openmoko-2.6.32/0003-usbhost.patch.patch | 233 ++ .../0004-Work-on-Glamo-core-for-DRM.patch | 171 - .../0004-ar6000_delay.patch.patch | 211 ++ .../0005-Add-JBT6k74-hook-for-use-by-KMS.patch | 49 - .../0005-save_regs.patch.patch | 140 + ...se-dev_set_drvdata-instead-of-setting-dri.patch | 29 - ...nfigs-enable-LEDS_S3C24XX-and-dummy-batte.patch | 66 + .../0007-DRM-for-platform-devices.patch | 458 +++ ...-select-DRM_KMS_HELPER-for-crtc-functions.patch | 24 - ...sh-when-reading-Glamo-registers-via-sysfs.patch | 38 - .../0008-Glamo-DRM-and-KMS-driver.patch | 3869 ++++++++++++++++++++ .../0009-A-couple-of-GEM-refcounting-fixes.patch | 42 - .../0009-Work-on-Glamo-core-for-DRM.patch | 162 + .../0010-JBT6k74-work-for-KMS.patch | 540 +++ .../0010-Simplify-the-JBT6k74-driver.patch | 667 ---- ...-if-userspace-provides-a-pixel-clock-valu.patch | 79 - ...sh-when-reading-Glamo-registers-via-sysfs.patch | 38 + ...0012-Fix-dynamic-command-queue-allocation.patch | 131 + ...rt-all-FB-modes-given-by-the-lower-levels.patch | 102 - .../0013-Change-connector-type-to-LVDS.patch | 29 - .../0013-Debug-statements-for-testing.patch | 78 + ...-JBT-hooks-and-allow-resolution-switching.patch | 223 -- .../0014-Fix-claim-of-2D-register-resource.patch | 27 + ...display-before-trying-to-set-mode-or-base.patch | 103 - .../linux-openmoko-2.6.32/0016-accels.patch.patch | 1759 --------- .../linux-openmoko-2.6.32/0017-usbhost.patch.patch | 233 -- .../0018-ar6000_delay.patch.patch | 211 -- .../0019-save_regs.patch.patch | 140 - ...0020-Fix-KMS-framebuffer-physical-address.patch | 38 - .../0021-Reject-modes-with-clock-0.patch | 25 - ...BT6k74-tweaks-Make-resolution-switch-work.patch | 316 -- ...023-Remove-a-couple-of-debugging-messages.patch | 35 - ...le-dummy-frames-when-switching-resolution.patch | 26 - .../0025-Almost-make-rotation-work.patch | 212 -- ...0026-gta02-defconfigs-enable-LEDS_S3C24XX.patch | 48 - recipes/linux/linux-openmoko-2.6.32_git.bb | 44 +- 40 files changed, 7732 insertions(+), 8875 deletions(-) delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0002-DRM-for-platform-devices.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0002-accels.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0003-Glamo-DRM-and-KMS-driver.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0003-usbhost.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0004-Work-on-Glamo-core-for-DRM.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0004-ar6000_delay.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0005-Add-JBT6k74-hook-for-use-by-KMS.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0005-save_regs.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0006-glamo-drm-use-dev_set_drvdata-instead-of-setting-dri.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0006-gta02-defconfigs-enable-LEDS_S3C24XX-and-dummy-batte.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0007-DRM-for-platform-devices.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0007-glamo-drm-select-DRM_KMS_HELPER-for-crtc-functions.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0008-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0008-Glamo-DRM-and-KMS-driver.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0009-A-couple-of-GEM-refcounting-fixes.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0009-Work-on-Glamo-core-for-DRM.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0010-JBT6k74-work-for-KMS.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0010-Simplify-the-JBT6k74-driver.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0011-Don-t-choke-if-userspace-provides-a-pixel-clock-valu.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0011-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0012-Fix-dynamic-command-queue-allocation.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0012-Report-all-FB-modes-given-by-the-lower-levels.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0013-Change-connector-type-to-LVDS.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0013-Debug-statements-for-testing.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0014-Clean-up-JBT-hooks-and-allow-resolution-switching.patch create mode 100644 recipes/linux/linux-openmoko-2.6.32/0014-Fix-claim-of-2D-register-resource.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0015-Enable-display-before-trying-to-set-mode-or-base.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0016-accels.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0017-usbhost.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0018-ar6000_delay.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0019-save_regs.patch.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0020-Fix-KMS-framebuffer-physical-address.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0021-Reject-modes-with-clock-0.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0022-JBT6k74-tweaks-Make-resolution-switch-work.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0023-Remove-a-couple-of-debugging-messages.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0024-Enable-dummy-frames-when-switching-resolution.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0025-Almost-make-rotation-work.patch delete mode 100644 recipes/linux/linux-openmoko-2.6.32/0026-gta02-defconfigs-enable-LEDS_S3C24XX.patch diff --git a/recipes/linux/linux-openmoko-2.6.32/0001-wm8753-fix-build-with-gcc-4.4.2-which-works-ok-with-.patch b/recipes/linux/linux-openmoko-2.6.32/0001-wm8753-fix-build-with-gcc-4.4.2-which-works-ok-with-.patch index c6a16ab4d5..52fe6262cc 100644 --- a/recipes/linux/linux-openmoko-2.6.32/0001-wm8753-fix-build-with-gcc-4.4.2-which-works-ok-with-.patch +++ b/recipes/linux/linux-openmoko-2.6.32/0001-wm8753-fix-build-with-gcc-4.4.2-which-works-ok-with-.patch @@ -1,7 +1,7 @@ -From b3b22a8f23e6b49d21bbfe70f278a0d79419e3df Mon Sep 17 00:00:00 2001 +From 16722526979959805c493deabaac8cf9ba2f8ef6 Mon Sep 17 00:00:00 2001 From: Martin Jansa Date: Sat, 7 Nov 2009 20:33:06 +0100 -Subject: [PATCH 1/9] wm8753: fix build with gcc-4.4.2, which works ok with 4.1.2 +Subject: [PATCH 01/14] wm8753: fix build with gcc-4.4.2, which works ok with 4.1.2 Signed-off-by: Martin Jansa --- @@ -24,5 +24,5 @@ index 5ad677c..e148406 100644 K = Kpart & 0xFFFFFFFF; -- -1.6.6.1 +1.7.1 diff --git a/recipes/linux/linux-openmoko-2.6.32/0002-DRM-for-platform-devices.patch b/recipes/linux/linux-openmoko-2.6.32/0002-DRM-for-platform-devices.patch deleted file mode 100644 index 4e47a088d0..0000000000 --- a/recipes/linux/linux-openmoko-2.6.32/0002-DRM-for-platform-devices.patch +++ /dev/null @@ -1,458 +0,0 @@ -From 660570997a5c998aaecc94798b6ea8d60b0da053 Mon Sep 17 00:00:00 2001 -From: Thomas White -Date: Tue, 20 Oct 2009 15:52:30 +0200 -Subject: [PATCH 2/9] 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 ---- - 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 96eddd1..8b050ad 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 8417cc4..5a3b203 100644 ---- a/drivers/gpu/drm/drm_bufs.c -+++ b/drivers/gpu/drm/drm_bufs.c -@@ -188,7 +188,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 a75ca63..26005d9 100644 ---- a/drivers/gpu/drm/drm_drv.c -+++ b/drivers/gpu/drm/drm_drv.c -@@ -247,6 +247,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; -@@ -280,11 +281,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 55bb8a8..5e3d65a 100644 ---- a/drivers/gpu/drm/drm_stub.c -+++ b/drivers/gpu/drm/drm_stub.c -@@ -230,8 +230,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; -@@ -449,6 +451,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 7e42b7e..c08e7b7 100644 ---- a/drivers/gpu/drm/drm_sysfs.c -+++ b/drivers/gpu/drm/drm_sysfs.c -@@ -486,7 +486,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 7ad3faa..1d9a229 100644 ---- a/include/drm/drmP.h -+++ b/include/drm/drmP.h -@@ -55,6 +55,7 @@ - #include - #include - #include -+#include - #if defined(__alpha__) || defined(__powerpc__) - #include /* For pte_wrprotect */ - #endif -@@ -143,6 +144,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... */ -@@ -1008,6 +1010,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 */ -@@ -1118,12 +1121,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 int drm_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -@@ -1342,6 +1353,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.6.6.1 - diff --git a/recipes/linux/linux-openmoko-2.6.32/0002-accels.patch.patch b/recipes/linux/linux-openmoko-2.6.32/0002-accels.patch.patch new file mode 100644 index 0000000000..9644473eda --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.32/0002-accels.patch.patch @@ -0,0 +1,1759 @@ +From b96dbc75c274014171a53da13686bd90d239c023 Mon Sep 17 00:00:00 2001 +From: Radek Polak +Date: Fri, 9 Apr 2010 09:15:40 +0200 +Subject: [PATCH 02/14] 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 +--- + arch/arm/mach-s3c2410/include/mach/spi-gpio.h | 3 +- + arch/arm/mach-s3c2442/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 980a099..0ff8949 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-s3c2442/mach-gta02.c b/arch/arm/mach-s3c2442/mach-gta02.c +index 7965cad..0675181 100644 +--- a/arch/arm/mach-s3c2442/mach-gta02.c ++++ b/arch/arm/mach-s3c2442/mach-gta02.c +@@ -63,6 +63,7 @@ + + #include + #include ++#include + + #include + #include +@@ -120,6 +121,22 @@ + #include + #endif + ++#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 ++ + struct pcf50633 *gta02_pcf; + + /* +@@ -775,6 +792,60 @@ const 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", +@@ -785,6 +856,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 = >a02_spigpio_cfg, ++ }, + }; + + /* BQ27000 Battery */ +@@ -1135,6 +1281,7 @@ static struct platform_device *gta02_devices[] __initdata = { + static struct platform_device *gta02_devices_pmu_children[] = { + &s3c_device_ts, + >a02_glamo_dev, ++ >a02_spi_gpio_dev, + &s3c_device_timer[2], + >a02_hdq_device, + >a02_gps_userspace_consumer +@@ -1361,6 +1508,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; ++ } ++ + s3c_device_ts.name = "s3c2440-ts"; + + bus_register_notifier(&platform_bus_type, >a02_device_register_notifier); +diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig +index a9bb254..2e9bc5d 100644 +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -317,4 +317,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 a8b8485..7e63293 100644 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -30,4 +30,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 ++ * converted to private bitbang by: ++ * Andy Green ++ * ability to set acceleration threshold added by: ++ * Simon Kagstrom ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* 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; ++ ++ /* make sure we're powered up and generate data ready */ ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1); ++ ++ /* If the threshold is zero, let the device generated an interrupt ++ * on each datum */ ++ if (lis->threshold == 0) { ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0); ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY); ++ } else { ++ __reg_write(lis, LIS302DL_REG_CTRL2, ++ LIS302DL_CTRL2_HPFF1); ++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, ++ __mg_to_threshold(lis, lis->threshold)); ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, ++ __ms_to_duration(lis, lis->duration)); ++ ++ /* Clear the HP filter "starting point" */ ++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET); ++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, ++ LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE | ++ LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR); ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12); ++ } ++} ++ ++#if 0 ++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); ++} ++#endif ++ ++ ++static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis) ++{ ++ u8 data[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 2] = {0xC0 | LIS302DL_REG_STATUS}; ++ u8 *read = data + 1; ++ unsigned long flags; ++ int mg_per_sample = __threshold_to_mg(lis, 1); ++ struct spi_message msg; ++ struct spi_transfer t; ++ ++ spi_message_init(&msg); ++ memset(&t, 0, sizeof t); ++ t.len = sizeof(data); ++ spi_message_add_tail(&t, &msg); ++ t.tx_buf = &data[0]; ++ t.rx_buf = &data[0]; ++ ++ /* grab the set of register containing status and XYZ data */ ++ ++ local_irq_save(flags); ++ ++ /* Should complete without blocking */ ++ if (spi_non_blocking_transfer(lis->spi, &msg) < 0) ++ dev_err(lis->dev, "Error reading registers\n"); ++ ++ local_irq_restore(flags); ++ ++ /* ++ * at the minute the test below fails 50% of the time due to ++ * a problem with level interrupts causing ISRs to get called twice. ++ * This is a workaround for that, but actually this test is still ++ * valid and the information can be used for overrrun stats. ++ */ ++ ++ /* has any kind of overrun been observed by the lis302dl? */ ++ if (read[0] & (LIS302DL_STATUS_XOR | ++ LIS302DL_STATUS_YOR | ++ LIS302DL_STATUS_ZOR)) ++ lis->overruns++; ++ ++ /* we have a valid sample set? */ ++ if (read[0] & LIS302DL_STATUS_XYZDA) { ++ input_report_abs(lis->input_dev, ABS_X, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]); ++ input_report_abs(lis->input_dev, ABS_Y, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]); ++ input_report_abs(lis->input_dev, ABS_Z, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]); ++ ++ input_sync(lis->input_dev); ++ } ++ ++ if (lis->threshold) ++ /* acknowledge the wakeup source */ ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1); ++} ++ ++static irqreturn_t lis302dl_interrupt(int irq, void *_lis) ++{ ++ struct lis302dl_info *lis = _lis; ++ ++ lis302dl_bitbang_read_sample(lis); ++ return IRQ_HANDLED; ++} ++ ++/* sysfs */ ++ ++static ssize_t show_overruns(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", lis->overruns); ++} ++ ++static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL); ++ ++static ssize_t show_rate(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ u8 ctrl1; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1); ++ local_irq_restore(flags); ++ ++ 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); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (!strcmp(buf, "400\n")) { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, ++ LIS302DL_CTRL1_DR); ++ lis->flags |= LIS302DL_F_DR; ++ } else { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, ++ 0); ++ lis->flags &= ~LIS302DL_F_DR; ++ } ++ local_irq_restore(flags); ++ ++ 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; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1); ++ local_irq_restore(flags); ++ ++ 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); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (!strcmp(buf, "9.2\n")) { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, ++ LIS302DL_CTRL1_FS); ++ lis->flags |= LIS302DL_F_FS; ++ } else { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, ++ 0); ++ lis->flags &= ~LIS302DL_F_FS; ++ } ++ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __enable_data_collection(lis); ++ ++ local_irq_restore(flags); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale); ++ ++static ssize_t show_threshold(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ /* Display the device view of the threshold setting */ ++ return sprintf(buf, "%d\n", __threshold_to_mg(lis, ++ __mg_to_threshold(lis, lis->threshold))); ++} ++ ++static ssize_t set_threshold(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ /* 8g is the maximum if FS is 1 */ ++ if (val > 8000) ++ return -ERANGE; ++ ++ /* Set the threshold and write it out if the device is used */ ++ lis->threshold = val; ++ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ __enable_data_collection(lis); ++ local_irq_restore(flags); ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold); ++ ++static ssize_t show_duration(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", __duration_to_ms(lis, ++ __ms_to_duration(lis, lis->duration))); ++} ++ ++static ssize_t set_duration(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ if (val > 2550) ++ return -ERANGE; ++ ++ lis->duration = val; ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, ++ __ms_to_duration(lis, lis->duration)); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration); ++ ++static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ int n = 0; ++ u8 reg[0x40]; ++ char *end = buf; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ for (n = 0; n < sizeof(reg); n++) ++ reg[n] = __reg_read(lis, n); ++ ++ local_irq_restore(flags); ++ ++ for (n = 0; n < sizeof(reg); n += 16) { ++ hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0); ++ end += strlen(end); ++ *end++ = '\n'; ++ *end++ = '\0'; ++ } ++ ++ return end - buf; ++} ++static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL); ++ ++/* Configure freefall/wakeup interrupts */ ++static ssize_t set_wakeup_threshold(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int threshold; ++ ++ if (sscanf(buf, "%u\n", &threshold) != 1) ++ return -EINVAL; ++ ++ if (threshold > 8000) ++ return -ERANGE; ++ ++ /* Zero turns the feature off */ ++ if (threshold == 0) { ++ if (lis->flags & LIS302DL_F_IRQ_WAKE) { ++ disable_irq_wake(lis->pdata->interrupt); ++ lis->flags &= ~LIS302DL_F_IRQ_WAKE; ++ } ++ ++ return count; ++ } ++ ++ lis->wakeup.threshold = threshold; ++ ++ if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) { ++ enable_irq_wake(lis->pdata->interrupt); ++ lis->flags |= LIS302DL_F_IRQ_WAKE; ++ } ++ ++ return count; ++} ++ ++static ssize_t show_wakeup_threshold(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ /* All events off? */ ++ if (lis->wakeup.threshold == 0) ++ return sprintf(buf, "off\n"); ++ ++ return sprintf(buf, "%u\n", lis->wakeup.threshold); ++} ++ ++static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold, ++ set_wakeup_threshold); ++ ++static ssize_t set_wakeup_duration(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int duration; ++ ++ if (sscanf(buf, "%u\n", &duration) != 1) ++ return -EINVAL; ++ ++ if (duration > 2550) ++ return -ERANGE; ++ ++ lis->wakeup.duration = duration; ++ ++ return count; ++} ++ ++static ssize_t show_wakeup_duration(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", lis->wakeup.duration); ++} ++ ++static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration, ++ set_wakeup_duration); ++ ++static struct attribute *lis302dl_sysfs_entries[] = { ++ &dev_attr_sample_rate.attr, ++ &dev_attr_full_scale.attr, ++ &dev_attr_threshold.attr, ++ &dev_attr_duration.attr, ++ &dev_attr_dump.attr, ++ &dev_attr_wakeup_threshold.attr, ++ &dev_attr_wakeup_duration.attr, ++ &dev_attr_overruns.attr, ++ NULL ++}; ++ ++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 = input_get_drvdata(inp); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ __enable_data_collection(lis); ++ lis->flags |= LIS302DL_F_INPUT_OPEN; ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static void lis302dl_input_close(struct input_dev *inp) ++{ ++ struct lis302dl_info *lis = input_get_drvdata(inp); ++ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ /* since the input core already serializes access and makes sure we ++ * only see close() for the close of the last user, we can safely ++ * disable the data ready events */ ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00); ++ lis->flags &= ~LIS302DL_F_INPUT_OPEN; ++ ++ /* 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); ++ } ++ local_irq_restore(flags); ++} ++ ++/* get the device to reload its coefficients from EEPROM and wait for it ++ * to complete ++ */ ++ ++static int __lis302dl_reset_device(struct lis302dl_info *lis) ++{ ++ int timeout = 10; ++ ++ __reg_write(lis, LIS302DL_REG_CTRL2, ++ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS); ++ ++ while ((__reg_read(lis, LIS302DL_REG_CTRL2) ++ & LIS302DL_CTRL2_BOOT) && (timeout--)) ++ mdelay(1); ++ ++ return !!(timeout < 0); ++} ++ ++static int __devinit lis302dl_probe(struct spi_device *spi) ++{ ++ int rc; ++ struct lis302dl_info *lis; ++ u_int8_t wai; ++ unsigned long flags; ++ struct lis302dl_platform_data *pdata = spi->dev.platform_data; ++ ++ spi->mode = SPI_MODE_3; ++ rc = spi_setup(spi); ++ if (rc < 0) { ++ dev_err(&spi->dev, "spi_setup failed\n"); ++ return rc; ++ } ++ ++ lis = kzalloc(sizeof(*lis), GFP_KERNEL); ++ if (!lis) ++ return -ENOMEM; ++ ++ lis->dev = &spi->dev; ++ lis->spi = spi; ++ ++ dev_set_drvdata(lis->dev, lis); ++ ++ lis->pdata = pdata; ++ ++ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group); ++ if (rc) { ++ dev_err(lis->dev, "error creating sysfs group\n"); ++ goto bail_free_lis; ++ } ++ ++ /* initialize input layer details */ ++ lis->input_dev = input_allocate_device(); ++ if (!lis->input_dev) { ++ dev_err(lis->dev, "Unable to allocate input device\n"); ++ goto bail_sysfs; ++ } ++ ++ input_set_drvdata(lis->input_dev, lis); ++ lis->input_dev->name = pdata->name; ++ /* SPI Bus not defined as a valid bus for input subsystem*/ ++ lis->input_dev->id.bustype = BUS_I2C; /* lie about it */ ++ lis->input_dev->open = lis302dl_input_open; ++ lis->input_dev->close = lis302dl_input_close; ++ ++ rc = input_register_device(lis->input_dev); ++ if (rc) { ++ dev_err(lis->dev, "error %d registering input device\n", rc); ++ goto bail_inp_dev; ++ } ++ ++ local_irq_save(flags); ++ /* Configure our IO */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ wai = __reg_read(lis, LIS302DL_REG_WHO_AM_I); ++ if (wai != LIS302DL_WHO_AM_I_MAGIC) { ++ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai); ++ dev_set_drvdata(lis->dev, NULL); ++ rc = -ENODEV; ++ local_irq_restore(flags); ++ goto bail_inp_reg; ++ } ++ ++ set_bit(EV_ABS, lis->input_dev->evbit); ++ input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0); ++ input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0); ++ input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0); ++ ++ ++ lis->threshold = 0; ++ lis->duration = 0; ++ memset(&lis->wakeup, 0, sizeof(lis->wakeup)); ++ ++ if (__lis302dl_reset_device(lis)) ++ dev_err(lis->dev, "device BOOT reload failed\n"); ++ ++ /* force us powered */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | ++ LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen); ++ mdelay(1); ++ ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0); ++ __reg_write(lis, LIS302DL_REG_CTRL3, ++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL); ++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0); ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00); ++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0); ++ ++ /* start off in powered down mode; we power up when someone opens us */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen); ++ ++ if (pdata->open_drain) ++ /* switch interrupt to open collector, active-low */ ++ __reg_write(lis, LIS302DL_REG_CTRL3, ++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL); ++ else ++ /* push-pull, active-low */ ++ __reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL); ++ ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_GND); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND); ++ ++ __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_read(lis, LIS302DL_REG_CLICK_SRC); ++ local_irq_restore(flags); ++ ++ dev_info(lis->dev, "Found %s\n", pdata->name); ++ ++ lis->pdata = pdata; ++ ++ set_irq_handler(lis->pdata->interrupt, handle_level_irq); ++ ++ rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt, ++ IRQF_TRIGGER_LOW, "lis302dl", lis); ++ ++ if (rc < 0) { ++ dev_err(lis->dev, "error requesting IRQ %d\n", ++ lis->pdata->interrupt); ++ goto bail_inp_reg; ++ } ++ return 0; ++ ++bail_inp_reg: ++ input_unregister_device(lis->input_dev); ++bail_inp_dev: ++ input_free_device(lis->input_dev); ++bail_sysfs: ++ sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group); ++bail_free_lis: ++ kfree(lis); ++ return rc; ++} ++ ++static int __devexit lis302dl_remove(struct spi_device *spi) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ ++ /* Disable interrupts */ ++ if (lis->flags & LIS302DL_F_IRQ_WAKE) ++ disable_irq_wake(lis->pdata->interrupt); ++ free_irq(lis->pdata->interrupt, lis); ++ ++ /* Reset and power down the device */ ++ local_irq_save(flags); ++ __reg_write(lis, LIS302DL_REG_CTRL3, 0x00); ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0x00); ++ __reg_write(lis, LIS302DL_REG_CTRL1, 0x00); ++ local_irq_restore(flags); ++ ++ /* Cleanup resources */ ++ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group); ++ input_unregister_device(lis->input_dev); ++ if (lis->input_dev) ++ input_free_device(lis->input_dev); ++ dev_set_drvdata(lis->dev, NULL); ++ kfree(lis); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++static u8 regs_to_save[] = { ++ LIS302DL_REG_CTRL2, ++ LIS302DL_REG_CTRL3, ++ LIS302DL_REG_FF_WU_CFG_1, ++ LIS302DL_REG_FF_WU_THS_1, ++ LIS302DL_REG_FF_WU_DURATION_1, ++ LIS302DL_REG_FF_WU_CFG_2, ++ LIS302DL_REG_FF_WU_THS_2, ++ LIS302DL_REG_FF_WU_DURATION_2, ++ LIS302DL_REG_CLICK_CFG, ++ LIS302DL_REG_CLICK_THSY_X, ++ LIS302DL_REG_CLICK_THSZ, ++ LIS302DL_REG_CLICK_TIME_LIMIT, ++ LIS302DL_REG_CLICK_LATENCY, ++ LIS302DL_REG_CLICK_WINDOW, ++ LIS302DL_REG_CTRL1, ++}; ++ ++static int lis302dl_suspend(struct spi_device *spi, pm_message_t state) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ u_int8_t tmp; ++ int n; ++ ++ /* determine if we want to wake up from the accel. */ ++ if (lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; ++ ++ disable_irq(lis->pdata->interrupt); ++ local_irq_save(flags); ++ ++ /* ++ * When we share SPI over multiple sensors, there is a race here ++ * that one or more sensors will lose. In that case, the shared ++ * SPI bus GPIO will be in sleep mode and partially pulled down. So ++ * we explicitly put our IO into "wake" mode here before the final ++ * traffic to the sensor. ++ */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ /* save registers */ ++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++) ++ lis->regs[regs_to_save[n]] = ++ __reg_read(lis, regs_to_save[n]); ++ ++ /* power down or enable wakeup */ ++ ++ if (lis->wakeup.threshold == 0) { ++ tmp = __reg_read(lis, LIS302DL_REG_CTRL1); ++ tmp &= ~LIS302DL_CTRL1_PD; ++ __reg_write(lis, LIS302DL_REG_CTRL1, tmp); ++ } else ++ __enable_wakeup(lis); ++ ++ /* place our IO to the device in sleep-compatible states */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 0); ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static int lis302dl_resume(struct spi_device *spi) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ int n; ++ ++ if (lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; ++ ++ local_irq_save(flags); ++ ++ /* get our IO to the device back in operational states */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ /* resume from powerdown first! */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, ++ LIS302DL_CTRL1_PD | ++ LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen); ++ mdelay(1); ++ ++ if (__lis302dl_reset_device(lis)) ++ dev_err(&spi->dev, "device BOOT reload failed\n"); ++ ++ /* restore registers after resume */ ++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++) ++ __reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]); ++ ++ /* if someone had us open, reset the non-wake threshold stuff */ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __enable_data_collection(lis); ++ ++ local_irq_restore(flags); ++ enable_irq(lis->pdata->interrupt); ++ ++ return 0; ++} ++#else ++#define lis302dl_suspend NULL ++#define lis302dl_resume NULL ++#endif ++ ++static struct spi_driver lis302dl_spi_driver = { ++ .driver = { ++ .name = "lis302dl", ++ .owner = THIS_MODULE, ++ }, ++ ++ .probe = lis302dl_probe, ++ .remove = __devexit_p(lis302dl_remove), ++ .suspend = lis302dl_suspend, ++ .resume = lis302dl_resume, ++}; ++ ++static int __devinit lis302dl_init(void) ++{ ++ return spi_register_driver(&lis302dl_spi_driver); ++} ++ ++static void __exit lis302dl_exit(void) ++{ ++ spi_unregister_driver(&lis302dl_spi_driver); ++} ++ ++MODULE_AUTHOR("Harald Welte "); ++MODULE_LICENSE("GPL"); ++ ++module_init(lis302dl_init); ++module_exit(lis302dl_exit); +diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c +index f1db395..5c50329 100644 +--- a/drivers/spi/spi_bitbang.c ++++ b/drivers/spi/spi_bitbang.c +@@ -253,134 +253,139 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) + * Drivers can provide word-at-a-time i/o primitives, or provide + * transfer-at-a-time ones to leverage dma or fifo hardware. + */ +-static void bitbang_work(struct work_struct *work) ++/* Synchronous non blocking transfer */ ++int ++spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m) + { +- struct spi_bitbang *bitbang = +- container_of(work, struct spi_bitbang, work); +- unsigned long flags; +- int do_setup = -1; +- int (*setup_transfer)(struct spi_device *, +- struct spi_transfer *); ++ struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); ++ struct spi_transfer *t; ++ unsigned long flags; ++ int cs_change = 1; ++ int status; ++ int nsecs; ++ int (*setup_transfer)(struct spi_device *, struct spi_transfer *); ++ ++ /* FIXME this is made-up ... the correct value is known to ++ * word-at-a-time bitbang code, and presumably chipselect() ++ * should enforce these requirements too? ++ */ ++ nsecs = 100; ++ cs_change = 1; ++ status = 0; ++ setup_transfer = NULL; ++ ++ local_irq_save(flags); ++ list_for_each_entry (t, &m->transfers, transfer_list) { ++ /* override or restore speed and wordsize */ ++ if (t->speed_hz || t->bits_per_word) { ++ setup_transfer = bitbang->setup_transfer; ++ if (!setup_transfer) { ++ status = -ENOPROTOOPT; ++ break; ++ } ++ } ++ if (setup_transfer) { ++ status = setup_transfer(spi, t); ++ if (status < 0) ++ break; ++ } + +- setup_transfer = bitbang->setup_transfer; ++ /* set up default clock polarity, and activate chip; ++ * this implicitly updates clock and spi modes as ++ * previously recorded for this device via setup(). ++ * (and also deselects any other chip that might be ++ * selected ...) ++ */ + +- spin_lock_irqsave(&bitbang->lock, flags); +- bitbang->busy = 1; +- while (!list_empty(&bitbang->queue)) { +- struct spi_message *m; +- struct spi_device *spi; +- unsigned nsecs; +- struct spi_transfer *t = NULL; +- unsigned tmp; +- unsigned cs_change; +- int status; ++ if (cs_change) { ++ bitbang->chipselect(spi, BITBANG_CS_ACTIVE); ++ ndelay(nsecs); ++ } + +- m = container_of(bitbang->queue.next, struct spi_message, +- queue); +- list_del_init(&m->queue); +- spin_unlock_irqrestore(&bitbang->lock, flags); ++ cs_change = t->cs_change; ++ if (!t->tx_buf && !t->rx_buf && t->len) { ++ status = -EINVAL; ++ break; ++ } + +- /* FIXME this is made-up ... the correct value is known to +- * word-at-a-time bitbang code, and presumably chipselect() +- * should enforce these requirements too? ++ /* transfer data. the lower level code handles any ++ * new dma mappings it needs. our caller always gave ++ * us dma-safe buffers. + */ +- nsecs = 100; ++ if (t->len) { ++ /* REVISIT dma API still needs a designated ++ * DMA_ADDR_INVALID; ~0 might be better. ++ */ ++ if (!m->is_dma_mapped) ++ t->rx_dma = t->tx_dma = 0; ++ status = bitbang->txrx_bufs(spi, t); ++ } + +- spi = m->spi; +- tmp = 0; +- cs_change = 1; ++ if (status > 0) ++ m->actual_length += status; ++ if (status != t->len) { ++ /* always report some kind of error */ ++ if (status >= 0) ++ status = -EREMOTEIO; ++ break; ++ } + status = 0; ++ /* protocol tweaks before next transfer */ ++ if (t->delay_usecs) ++ udelay(t->delay_usecs); ++ if (!cs_change) ++ continue; ++ if (t->transfer_list.next == &m->transfers) ++ break; ++ /* sometimes a short mid-message deselect of the chip ++ * may be needed to terminate a mode or command ++ */ ++ ndelay(nsecs); ++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ++ ndelay(nsecs); ++ } + +- list_for_each_entry (t, &m->transfers, transfer_list) { +- +- /* override speed or wordsize? */ +- if (t->speed_hz || t->bits_per_word) +- do_setup = 1; +- +- /* init (-1) or override (1) transfer params */ +- if (do_setup != 0) { +- if (!setup_transfer) { +- status = -ENOPROTOOPT; +- break; +- } +- status = setup_transfer(spi, t); +- if (status < 0) +- break; +- } ++ m->status = status; ++ if (m->complete) ++ m->complete(m->context); + +- /* set up default clock polarity, and activate chip; +- * this implicitly updates clock and spi modes as +- * previously recorded for this device via setup(). +- * (and also deselects any other chip that might be +- * selected ...) +- */ +- if (cs_change) { +- bitbang->chipselect(spi, BITBANG_CS_ACTIVE); +- ndelay(nsecs); +- } +- cs_change = t->cs_change; +- if (!t->tx_buf && !t->rx_buf && t->len) { +- status = -EINVAL; +- break; +- } ++ /* restore speed and wordsize */ ++ if (setup_transfer) ++ setup_transfer(spi, NULL); + +- /* transfer data. the lower level code handles any +- * new dma mappings it needs. our caller always gave +- * us dma-safe buffers. +- */ +- if (t->len) { +- /* REVISIT dma API still needs a designated +- * DMA_ADDR_INVALID; ~0 might be better. +- */ +- if (!m->is_dma_mapped) +- t->rx_dma = t->tx_dma = 0; +- status = bitbang->txrx_bufs(spi, t); +- } +- if (status > 0) +- m->actual_length += status; +- if (status != t->len) { +- /* always report some kind of error */ +- if (status >= 0) +- status = -EREMOTEIO; +- break; +- } +- status = 0; +- +- /* protocol tweaks before next transfer */ +- if (t->delay_usecs) +- udelay(t->delay_usecs); ++ /* normally deactivate chipselect ... unless no error and ++ * cs_change has hinted that the next message will probably ++ * be for this ch