From 894fcd09757550defb344445597e113bbae02c52 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Sun, 3 Aug 2008 16:31:31 +0000 Subject: files: add some stuff to device_table_add-mmc.txt and rename it to devices-table-collie.txt. conf/collie: use device-table-collie.txt packages/kexecboot:*create a new directory for everything kexecboot related *move initramfs-kexec-image and initramfs-kexec to this dir and rename them to *kexecboot *move linux-kexecboot to this dir *add forgotten patches for linux-kexecboot --- conf/machine/collie.conf | 2 +- files/device_table-collie.txt | 4 + files/device_table_add-mmc.txt | 2 - packages/images/initramfs-kexec-image.bb | 9 - packages/initrdscripts/initramfs-kexec_1.0.bb | 27 - packages/kexecboot/.mtn2git_empty | 0 packages/kexecboot/initramfs-kexecboot-image.bb | 9 + packages/kexecboot/initramfs_kexecboot_1.0.bb | 20 + packages/kexecboot/kexecboot_0.3.bb | 19 + .../linux-kexecboot-2.6.26/.mtn2git_empty | 0 .../binutils-buildid-arm.patch | 16 + .../kexecboot/linux-kexecboot-2.6.26/collie.patch | 1900 ++ .../linux-kexecboot-2.6.26/collie_keymap.patch | 420 + .../connectplus-prevent-oops-HACK.patch | 17 + .../connectplus-remove-ide-HACK.patch | 12 + .../linux-kexecboot-2.6.26/defconfig-akita | 1741 + .../linux-kexecboot-2.6.26/defconfig-bootcdx86 | 1994 ++ .../linux-kexecboot-2.6.26/defconfig-c7x0 | 1747 + .../linux-kexecboot-2.6.26/defconfig-collie | 810 + .../linux-kexecboot-2.6.26/defconfig-htcuniversal | 1308 + .../linux-kexecboot-2.6.26/defconfig-hx2000 | 1733 + .../linux-kexecboot-2.6.26/defconfig-poodle | 1757 + .../linux-kexecboot-2.6.26/defconfig-qemuarm | 1582 + .../linux-kexecboot-2.6.26/defconfig-qemux86 | 1993 ++ .../linux-kexecboot-2.6.26/defconfig-spitz | 1834 + .../linux-kexecboot-2.6.26/defconfig-zylonite | 1740 + .../hostap-monitor-mode.patch | 209 + .../linux-kexecboot-2.6.26/hrw-hostapcard.patch | 34 + .../linux-kexecboot-2.6.26/htcuni-acx.patch | 33527 +++++++++++++++++++ .../kexecboot/linux-kexecboot-2.6.26/htcuni.patch | 7899 +++++ .../linux-kexecboot-2.6.26/pxa-serial-hack.patch | 90 + .../linux-kexecboot-2.6.26/pxa_fb_overlay.patch | 26 + ...t-for-non-standard-xtals-to-16c950-driver.patch | 155 + .../linux-kexecboot-2.6.26/sharpsl-rc-r1.patch | 555 + .../linux-kexecboot-2.6.26/spitz_h_rewrite.patch | 497 + .../linux-kexecboot-2.6.26/versatile-armv6.patch | 17 + .../linux-kexecboot-2.6.26/zaurus-i2c-init.patch | 68 + .../linux-kexecboot-2.6.26/zylonite-boot.patch | 45 + .../zylonite_keypad-r0.patch | 1187 + .../linux-kexecboot-2.6.26/zylonite_mtd-r0.patch | 4093 +++ .../linux-kexecboot-2.6.26/zylonite_touch-r0.patch | 1548 + packages/kexecboot/linux-kexecboot.inc | 40 + packages/kexecboot/linux-kexecboot_2.6.26.bb | 175 + .../linux/linux-kexecboot-2.6.26/.mtn2git_empty | 0 packages/linux/linux-kexecboot.inc | 40 - packages/linux/linux-kexecboot_2.6.26.bb | 175 - 46 files changed, 70822 insertions(+), 254 deletions(-) create mode 100644 files/device_table-collie.txt delete mode 100644 files/device_table_add-mmc.txt delete mode 100644 packages/images/initramfs-kexec-image.bb delete mode 100644 packages/initrdscripts/initramfs-kexec_1.0.bb create mode 100644 packages/kexecboot/.mtn2git_empty create mode 100644 packages/kexecboot/initramfs-kexecboot-image.bb create mode 100644 packages/kexecboot/initramfs_kexecboot_1.0.bb create mode 100644 packages/kexecboot/kexecboot_0.3.bb create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/.mtn2git_empty create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/binutils-buildid-arm.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/collie.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/collie_keymap.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/connectplus-prevent-oops-HACK.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/connectplus-remove-ide-HACK.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-akita create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-bootcdx86 create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-c7x0 create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-collie create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-htcuniversal create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-hx2000 create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-poodle create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-qemuarm create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-qemux86 create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-spitz create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/defconfig-zylonite create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/hostap-monitor-mode.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/hrw-hostapcard.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/htcuni-acx.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/htcuni.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/pxa-serial-hack.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/pxa_fb_overlay.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/serial-add-support-for-non-standard-xtals-to-16c950-driver.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/sharpsl-rc-r1.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/spitz_h_rewrite.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/versatile-armv6.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/zaurus-i2c-init.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/zylonite-boot.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/zylonite_keypad-r0.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch create mode 100644 packages/kexecboot/linux-kexecboot-2.6.26/zylonite_touch-r0.patch create mode 100644 packages/kexecboot/linux-kexecboot.inc create mode 100644 packages/kexecboot/linux-kexecboot_2.6.26.bb delete mode 100644 packages/linux/linux-kexecboot-2.6.26/.mtn2git_empty delete mode 100644 packages/linux/linux-kexecboot.inc delete mode 100644 packages/linux/linux-kexecboot_2.6.26.bb diff --git a/conf/machine/collie.conf b/conf/machine/collie.conf index 3914184a22..34731c387f 100644 --- a/conf/machine/collie.conf +++ b/conf/machine/collie.conf @@ -21,6 +21,6 @@ ROOT_FLASH_SIZE = "14" DONT_CHECK_KERNELSIZE ?= "1" IMAGE_DEVICE_TABLES ?= "files/device_table-minimal.txt \ - files/device_table_add-mmc.txt" + files/device_table-collie.txt" XSERVER ?= "xserver-kdrive-fbdev" diff --git a/files/device_table-collie.txt b/files/device_table-collie.txt new file mode 100644 index 0000000000..86b06804ff --- /dev/null +++ b/files/device_table-collie.txt @@ -0,0 +1,4 @@ +# mmc numbers are assigned dynamicly so if you have other dynamic assigned block devices it may be wrong +/dev/mmcblk0p1 b 660 0 6 179 1 - - - +/dev/event0 c 660 0 0 13 64 - - - +/dev/fb0 c 660 0 0 29 0 - - - diff --git a/files/device_table_add-mmc.txt b/files/device_table_add-mmc.txt deleted file mode 100644 index b927971ad0..0000000000 --- a/files/device_table_add-mmc.txt +++ /dev/null @@ -1,2 +0,0 @@ -# mmc numbers are assigned dynamicly so if you have other dynamic assigned block devices it may be wrong -/dev/mmcblk0p1 b 660 0 6 179 1 - - - diff --git a/packages/images/initramfs-kexec-image.bb b/packages/images/initramfs-kexec-image.bb deleted file mode 100644 index 93cc348cda..0000000000 --- a/packages/images/initramfs-kexec-image.bb +++ /dev/null @@ -1,9 +0,0 @@ -#initramfs image which mounts the rootfilesystem and kexecs a kernel from there - -IMAGE_FSTYPES += " cpio.gz" -inherit image - -export IMAGE_BASENAME = "initramfs-kexec-image" - -IMAGE_INSTALL = "klibc-utils-static-sh klibc-utils-static-mount kexec-static initramfs-kexec" -IMAGE_LINGUAS = "" diff --git a/packages/initrdscripts/initramfs-kexec_1.0.bb b/packages/initrdscripts/initramfs-kexec_1.0.bb deleted file mode 100644 index 1b2ae27cf7..0000000000 --- a/packages/initrdscripts/initramfs-kexec_1.0.bb +++ /dev/null @@ -1,27 +0,0 @@ -DESCRIPTON = "A init script that mounts a device and kexecs a new kernel from it." -PR = "r6" - -do_compile() { - cat > init.sh << EOF -#!/bin/sh -/bin/mount -t proc proc /proc -/bin/mount -t ${ROOTFS} ${ROOTDEV} /mnt -/usr/sbin/kexec -l /mnt/boot/zImage -/usr/sbin/kexec -e -EOF -} - -do_install() { - install -m 0755 ${S}/init.sh ${D}/init - install -d ${D}/proc - install -d ${D}/mnt -} - -PACKAGE_ARCH = "all" - -FILES_${PN} = "/init /proc /mnt" - -ROOTDEV = "/dev/mmcblk0p1" -ROOTFS = "ext2" -#ROOTDEV = "mtd2" -#ROOTFS = "jffs2" diff --git a/packages/kexecboot/.mtn2git_empty b/packages/kexecboot/.mtn2git_empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/kexecboot/initramfs-kexecboot-image.bb b/packages/kexecboot/initramfs-kexecboot-image.bb new file mode 100644 index 0000000000..a55601955a --- /dev/null +++ b/packages/kexecboot/initramfs-kexecboot-image.bb @@ -0,0 +1,9 @@ +#initramfs image which mounts the rootfilesystem and kexecs a kernel from there + +IMAGE_FSTYPES += " cpio.gz" +inherit image + +export IMAGE_BASENAME = "initramfs-kexecboot-image" + +IMAGE_INSTALL = "klibc-utils-static-sh klibc-utils-static-mount kexec-static initramfs-kexecboot" +IMAGE_LINGUAS = "" diff --git a/packages/kexecboot/initramfs_kexecboot_1.0.bb b/packages/kexecboot/initramfs_kexecboot_1.0.bb new file mode 100644 index 0000000000..e1337419b8 --- /dev/null +++ b/packages/kexecboot/initramfs_kexecboot_1.0.bb @@ -0,0 +1,20 @@ +DESCRIPTON = "A init script that mounts a device and kexecs a new kernel from it." +PR = "r6" +RDEPENDS = "kexecboot" +do_compile() { + cat > init.sh << EOF +#!/bin/sh +/bin/mount -t proc proc /proc +/usr/bin/kexecboot -a 270 -i /dev/event0 +EOF +} + +do_install() { + install -m 0755 ${S}/init.sh ${D}/init + install -d ${D}/proc + install -d ${D}/mnt +} + +PACKAGE_ARCH = "all" + +FILES_${PN} = "/init /proc /mnt" diff --git a/packages/kexecboot/kexecboot_0.3.bb b/packages/kexecboot/kexecboot_0.3.bb new file mode 100644 index 0000000000..89b9e3b415 --- /dev/null +++ b/packages/kexecboot/kexecboot_0.3.bb @@ -0,0 +1,19 @@ +LICENSE = "GPL" +PR = "r0" +DEPENDS = "klibc" +inherit autotools + +# You can create your own *-img.h by doing +# ./make-image-header.sh .png HAND + +SRC_URI = "http://projects.linuxtogo.org/frs/download.php/221/kexecboot-${PV}.tar.gz" +S = "${WORKDIR}/kexecboot-${PV}" + + +export CC=${TARGET_PREFIX}klcc + +# standart oe cflags don't work with klcc +export CFLAGS="" +export CPPFLAGS="" +export LDFLAGS="" + diff --git a/packages/kexecboot/linux-kexecboot-2.6.26/.mtn2git_empty b/packages/kexecboot/linux-kexecboot-2.6.26/.mtn2git_empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/kexecboot/linux-kexecboot-2.6.26/binutils-buildid-arm.patch b/packages/kexecboot/linux-kexecboot-2.6.26/binutils-buildid-arm.patch new file mode 100644 index 0000000000..68e35e89e1 --- /dev/null +++ b/packages/kexecboot/linux-kexecboot-2.6.26/binutils-buildid-arm.patch @@ -0,0 +1,16 @@ +--- + arch/arm/kernel/vmlinux.lds.S | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.22/arch/arm/kernel/vmlinux.lds.S +=================================================================== +--- linux-2.6.22.orig/arch/arm/kernel/vmlinux.lds.S 2007-09-11 18:32:29.000000000 +0200 ++++ linux-2.6.22/arch/arm/kernel/vmlinux.lds.S 2007-09-11 18:33:42.000000000 +0200 +@@ -94,6 +94,7 @@ + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT ++ *(.note.*) + #ifdef CONFIG_MMU + *(.fixup) + #endif diff --git a/packages/kexecboot/linux-kexecboot-2.6.26/collie.patch b/packages/kexecboot/linux-kexecboot-2.6.26/collie.patch new file mode 100644 index 0000000000..6dad0027c6 --- /dev/null +++ b/packages/kexecboot/linux-kexecboot-2.6.26/collie.patch @@ -0,0 +1,1900 @@ +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index c7ad324..daa2e0a 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -998,7 +998,7 @@ config CPU_FREQ_SA1100 + + config CPU_FREQ_SA1110 + bool +- depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3) ++ depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3 || SA1100_COLLIE) + default y + + config CPU_FREQ_INTEGRATOR +diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c +index e508028..36f726c 100644 +--- a/arch/arm/mach-sa1100/dma.c ++++ b/arch/arm/mach-sa1100/dma.c +@@ -39,7 +39,7 @@ typedef struct { + + static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS]; + +-static spinlock_t dma_list_lock; ++static DEFINE_SPINLOCK(dma_list_lock); + + + static irqreturn_t dma_irq_handler(int irq, void *dev_id) +diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c +index 9caed30..79e19bf 100644 +--- a/drivers/input/keyboard/locomokbd.c ++++ b/drivers/input/keyboard/locomokbd.c +@@ -265,6 +265,7 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev) + for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) + set_bit(locomokbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); ++ locomo_writel(0, locomokbd->base + LOCOMO_KSC); + + /* attempt to get the interrupt */ + err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 9f93c29..33fc5d6 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -72,4 +72,10 @@ config MCP_UCB1200_TS + tristate "Touchscreen interface support" + depends on MCP_UCB1200 && INPUT + ++config MCP_COLLIE_TS ++ tristate "Touchscreen collie support" ++ depends on MCP_UCB1200 && INPUT && !MCP_UCB1200_TS ++ ---help--- ++ Driver for touchscreen on collie - sharp sl-5500. ++ + endmenu +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index 33daa2f..0885ccd 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -16,7 +16,7 @@ obj-$(CONFIG_MCP) += mcp-core.o + obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o + obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o + obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o +- ++obj-$(CONFIG_MCP_COLLIE_TS) += collie-ts.o + ifeq ($(CONFIG_SA1100_ASSABET),y) + obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o + endif +diff --git a/drivers/mfd/collie-ts.c b/drivers/mfd/collie-ts.c +new file mode 100644 +index 0000000..ddde5fc +--- /dev/null ++++ b/drivers/mfd/collie-ts.c +@@ -0,0 +1,449 @@ ++/* ++ * Touchscreen driver for UCB1x00-based touchscreens ++ * ++ * Copyright (C) 2001 Russell King, All Rights Reserved. ++ * Copyright (C) 2005 Pavel Machek ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 21-Jan-2002 : ++ * ++ * Added support for synchronous A/D mode. This mode is useful to ++ * avoid noise induced in the touchpanel by the LCD, provided that ++ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. ++ * It is important to note that the signal connected to the ADCSYNC ++ * pin should provide pulses even when the LCD is blanked, otherwise ++ * a pen touch needed to unblank the LCD will never be read. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ucb1x00.h" ++ ++struct ucb1x00_ts { ++ struct input_dev *idev; ++ struct ucb1x00 *ucb; ++ ++ wait_queue_head_t irq_wait; ++ struct task_struct *rtask; ++ u16 x_res; ++ u16 y_res; ++ ++ unsigned int adcsync:1; ++}; ++ ++static int adcsync; ++ ++/********************************** ++ ++ ................ ++ . . = 340 ++ . . ++ . ^. ++ . ^. ++ . ^. ++ . ^. ++ . . ++ . X. = 10 ++ . <<<<<<<< Y . ++ ................ ++ . Sharp =200 ++ . . ++ . - O - . ++ . . ++ ................ ++ ++**********************************/ ++ ++ ++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) ++{ ++ struct input_dev *idev = ts->idev; ++ ++ input_report_abs(idev, ABS_X, x); ++ input_report_abs(idev, ABS_Y, y); ++ input_report_abs(idev, ABS_PRESSURE, pressure); ++ input_report_key(idev, BTN_TOUCH, 1); ++ input_sync(idev); ++} ++ ++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) ++{ ++ struct input_dev *idev = ts->idev; ++ ++ input_report_abs(idev, ABS_PRESSURE, 0); ++ input_report_key(idev, BTN_TOUCH, 0); ++ input_sync(idev); ++} ++ ++/* ++ * Switch to interrupt mode. This set touchscreen to interrupt ++ * mode, so that chip is able to send interrupt. ++ */ ++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++} ++ ++/* ++ * Switch to pressure mode, and read pressure. We don't need to wait ++ * here, since both plates are being driven. ++ * ++ * set_read_pressure() in sharp code ++ */ ++static inline void ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0); ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW | ++ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); ++ ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_AD2 | ++ UCB_ADC_SYNC_ENA); ++ udelay(100); ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_AD2 | ++ UCB_ADC_SYNC_ENA | UCB_ADC_START); ++} ++ ++/* ++ * Switch to X position mode and measure Y plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline void ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); ++ ++ ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_TSPY | UCB_ADC_SYNC_ENA); ++ udelay(100); ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_TSPY | UCB_ADC_SYNC_ENA | ++ UCB_ADC_START); ++} ++ ++/* ++ * Switch to Y position mode and measure X plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline void ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); ++ ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | ++ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); ++ ++ ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_TSPX | UCB_ADC_SYNC_ENA); ++ udelay(100); ++ ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | ++ UCB_ADC_INP_TSPX | UCB_ADC_SYNC_ENA | ++ UCB_ADC_START); ++} ++ ++/* ++ * Switch to X plate resistance mode. Set MX to ground, PX to ++ * supply. Measure current. ++ */ ++static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); ++} ++ ++/* ++ * Switch to Y plate resistance mode. Set MY to ground, PY to ++ * supply. Measure current. ++ */ ++static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) ++{ ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); ++} ++ ++/* ++ * This is a RT kernel thread that handles the ADC accesses ++ * (mainly so we can use semaphores in the UCB1200 core code ++ * to serialise accesses to the ADC). ++ */ ++static int ucb1x00_thread(void *_ts) ++{ ++ struct ucb1x00_ts *ts = _ts; ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); ++ int state; ++ ++ /* ++ * We could run as a real-time thread. However, thus far ++ * this doesn't seem to be necessary. ++ */ ++ ++ add_wait_queue(&ts->irq_wait, &wait); ++ ++ while (!kthread_should_stop()) { ++ unsigned int data[3]; ++ ++ for (state=0; state<3; state++) { ++ ++ ucb1x00_adc_enable(ts->ucb); ++ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_ADC, UCB_FALLING); ++ switch (state) { ++ /* Order matters here; last measurement seems to be more noisy then the ++ rest, and we care about pressure least */ ++ case 2: ucb1x00_ts_read_pressure(ts); ++ break; ++ case 0: ucb1x00_ts_read_ypos(ts); ++ break; ++ case 1: ucb1x00_ts_read_xpos(ts); ++ break; ++ } ++ /* wait for adc */ ++ try_to_freeze(); ++ schedule_timeout(1000 * HZ); ++ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_ADC, UCB_FALLING); ++ data[state] = UCB_ADC_DAT(ucb1x00_reg_read(ts->ucb, UCB_ADC_DATA)); ++ ucb1x00_adc_disable(ts->ucb); ++ } ++ ++ /* If not pressed any more, try to sleep! */ ++ if (data[2] < 300) { ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING); ++ ucb1x00_ts_mode_int(ts); ++ ucb1x00_disable(ts->ucb); ++ ucb1x00_ts_event_release(ts); ++ try_to_freeze(); ++ schedule_timeout(1000 * HZ); ++ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING); ++ ucb1x00_enable(ts->ucb); ++ } else { ++ ucb1x00_ts_evt_add(ts, data[2], data[1], data[0]); ++ } ++ ucb1x00_disable(ts->ucb); ++ msleep(20); ++ ucb1x00_enable(ts->ucb); ++ } ++ ++ remove_wait_queue(&ts->irq_wait, &wait); ++ ++ ts->rtask = NULL; ++ return 0; ++} ++ ++/* ++ * We only detect touch screen _touches_ with this interrupt ++ * handler, and even then we just schedule our task. ++ */ ++static void ucb1x00_ts_irq(int idx, void *id) ++{ ++ struct ucb1x00_ts *ts = id; ++ wake_up(&ts->irq_wait); ++} ++ ++static void ucb1x00_adc_irq(int idx, void *id) ++{ ++ struct ucb1x00_ts *ts = id; ++ wake_up(&ts->irq_wait); ++} ++ ++static int ucb1x00_ts_open(struct input_dev *idev) ++{ ++ struct ucb1x00_ts *ts = input_get_drvdata(idev); ++ int ret = 0; ++ ++ BUG_ON(ts->rtask); ++ ++ init_waitqueue_head(&ts->irq_wait); ++ ++ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); ++ if (ret < 0) ++ return ret; ++ ++ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_ADC, ucb1x00_adc_irq, ts); ++ if (ret < 0) { ++ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ++ return ret; ++ } ++ ++ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING); ++ ++ /* ++ * If we do this at all, we should allow the user to ++ * measure and read the X and Y resistance at any time. ++ */ ++ ucb1x00_adc_enable(ts->ucb); ++ ts->x_res = ucb1x00_ts_read_xres(ts); ++ ts->y_res = ucb1x00_ts_read_yres(ts); ++ ucb1x00_adc_disable(ts->ucb); ++ ++ if (machine_is_collie()) { ++ ucb1x00_io_set_dir(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); ++ } ++ ++ ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); ++ if (!IS_ERR(ts->rtask)) { ++ ret = 0; ++ } else { ++ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ++ ts->rtask = NULL; ++ ret = -EFAULT; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Release touchscreen resources. Disable IRQs. ++ */ ++static void ucb1x00_ts_close(struct input_dev *idev) ++{ ++ struct ucb1x00_ts *ts = input_get_drvdata(idev); ++ ++ if (ts->rtask) ++ kthread_stop(ts->rtask); ++ ++ ucb1x00_enable(ts->ucb); ++ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ++ ucb1x00_free_irq(ts->ucb, UCB_IRQ_ADC, ts); ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); ++ ucb1x00_disable(ts->ucb); ++} ++ ++#ifdef CONFIG_PM ++static int ucb1x00_ts_resume(struct ucb1x00_dev *dev) ++{ ++ struct ucb1x00_ts *ts = dev->priv; ++ ++ if (ts->rtask != NULL) { ++ /* ++ * Restart the TS thread to ensure the ++ * TS interrupt mode is set up again ++ * after sleep. ++ */ ++ wake_up(&ts->irq_wait); ++ } ++ return 0; ++} ++#else ++#define ucb1x00_ts_resume NULL ++#endif ++ ++ ++/* ++ * Initialisation. ++ */ ++static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ++{ ++ struct ucb1x00_ts *ts; ++ struct input_dev *idev; ++ int err; ++ ++ ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); ++ idev = input_allocate_device(); ++ if (!ts || !idev) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ ts->ucb = dev->ucb; ++ ts->idev = idev; ++ ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; ++ ++ input_set_drvdata(idev, ts); ++ idev->name = "Touchscreen panel"; ++ idev->id.product = ts->ucb->id; ++ idev->open = ucb1x00_ts_open; ++ idev->close = ucb1x00_ts_close; ++ ++ __set_bit(EV_ABS, idev->evbit); ++ __set_bit(ABS_X, idev->absbit); ++ __set_bit(ABS_Y, idev->absbit); ++ __set_bit(ABS_PRESSURE, idev->absbit); ++ ++ input_set_abs_params(ts->idev, ABS_X, 0, 450, 0, 0); ++ input_set_abs_params(ts->idev, ABS_Y, 200, 800, 0, 0); ++ input_set_abs_params(ts->idev, ABS_PRESSURE, 400, 800, 0, 0); ++ ++ ++ err = input_register_device(idev); ++ if (err) ++ goto fail; ++ ++ dev->priv = ts; ++ ++ return 0; ++ ++ fail: ++ input_free_device(idev); ++ kfree(ts); ++ return err; ++} ++ ++static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) ++{ ++ struct ucb1x00_ts *ts = dev->priv; ++ ++ input_unregister_device(ts->idev); ++ kfree(ts); ++} ++ ++static struct ucb1x00_driver ucb1x00_ts_driver = { ++ .add = ucb1x00_ts_add, ++ .remove = ucb1x00_ts_remove, ++ .resume = ucb1x00_ts_resume, ++}; ++ ++static int __init ucb1x00_ts_init(void) ++{ ++ return ucb1x00_register_driver(&ucb1x00_ts_driver); ++} ++ ++static void __exit ucb1x00_ts_exit(void) ++{ ++ ucb1x00_unregister_driver(&ucb1x00_ts_driver); ++} ++ ++module_param(adcsync, int, 0444); ++module_init(ucb1x00_ts_init); ++module_exit(ucb1x00_ts_exit); ++ ++MODULE_AUTHOR("Russell King "); ++MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h +index a8ad8a0..137b043 100644 +--- a/drivers/mfd/ucb1x00.h ++++ b/drivers/mfd/ucb1x00.h +@@ -34,7 +34,10 @@ + #define UCB_IE_TCLIP (1 << 14) + #define UCB_IE_ACLIP (1 << 15) + ++/* UCB1200 irqs */ ++#define UCB_IRQ_ADC 11 + #define UCB_IRQ_TSPX 12 ++#define UCB_IRQ_TSMX 13 + + #define UCB_TC_A 0x05 + #define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ +diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c +index c7d5a52..215bec2 100644 +--- a/drivers/mtd/maps/sa1100-flash.c ++++ b/drivers/mtd/maps/sa1100-flash.c +@@ -210,6 +210,12 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r + goto err; + } + subdev->mtd->owner = THIS_MODULE; ++ ++#ifdef CONFIG_SA1100_COLLIE ++ /* collie flash starts locked */ ++ if (subdev->mtd->unlock) ++ subdev->mtd->unlock(subdev->mtd, 0xc0000, subdev->mtd->size - 0xc0000); ++#endif + + printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " + "%d-bit\n", phys, subdev->mtd->size >> 20, +diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c +index 3b4e55c..0ae741d 100644 +--- a/drivers/net/wireless/hostap/hostap_cs.c ++++ b/drivers/net/wireless/hostap/hostap_cs.c +@@ -35,7 +35,7 @@ static int ignore_cis_vcc; + module_param(ignore_cis_vcc, int, 0444); + MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); + +- ++int activar=0; + /* struct local_info::hw_priv */ + struct hostap_cs_priv { + dev_node_t node; +@@ -499,11 +499,13 @@ static int hostap_cs_probe(struct pcmcia_device *p_dev) + + PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); + p_dev->conf.IntType = INT_MEMORY_AND_IO; +- ++ ++ activar=0; + ret = prism2_config(p_dev); + if (ret) { + PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); + } ++ activar=1; + + return ret; + } +diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c +index 13d5882..6f24d66 100644 +--- a/drivers/net/wireless/hostap/hostap_hw.c ++++ b/drivers/net/wireless/hostap/hostap_hw.c +@@ -54,6 +54,7 @@ + #include "hostap.h" + #include "hostap_ap.h" + ++extern int activar; + + /* #define final_version */ + +@@ -1497,6 +1498,8 @@ static int prism2_hw_config(struct net_device *dev, int initial) + if (local->hw_downloading) + return 1; + ++ activar=1; ++ + if (prism2_hw_init(dev, initial)) { + return local->no_pri ? 0 : 1; + } +@@ -2628,8 +2631,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) + int events = 0; + u16 ev; + +- iface = netdev_priv(dev); +- local = iface->local; ++ ++ // Todos los parametros de entrada son correctos (no son nulos). De momento esta es la unica forma que conozco de detectar el problema. ++ if (!activar) { ++ printk("hostap_hw.c: INTERRUPT BEFORE DEVICE INIT!\n"); ++ return IRQ_HANDLED; ++ } ++ ++ iface = netdev_priv(dev); ++ local = iface->local; + + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); + +diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c +index 3a874fc..df58aa3 100644 +--- a/drivers/net/wireless/hostap/hostap_pci.c ++++ b/drivers/net/wireless/hostap/hostap_pci.c +@@ -19,6 +19,7 @@ + + #include "hostap_wlan.h" + ++int activar=1; + + static char *dev_info = "hostap_pci"; + +diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c +index cbf15d7..4475174 100644 +--- a/drivers/net/wireless/hostap/hostap_plx.c ++++ b/drivers/net/wireless/hostap/hostap_plx.c +@@ -21,7 +21,7 @@ + #include + + #include "hostap_wlan.h" +- ++int activar=1; + + static char *dev_info = "hostap_plx"; + +diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c +index c5b2a44..eecbe8c 100644 +--- a/drivers/pcmcia/sa1100_generic.c ++++ b/drivers/pcmcia/sa1100_generic.c +@@ -81,13 +81,14 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev) + return ret; + } + +-static struct device_driver sa11x0_pcmcia_driver = { +- .probe = sa11x0_drv_pcmcia_probe, +- .remove = soc_common_drv_pcmcia_remove, +- .name = "sa11x0-pcmcia", +- .bus = &platform_bus_type, +- .suspend = pcmcia_socket_dev_suspend, +- .resume = pcmcia_socket_dev_resume, ++static struct platform_driver sa11x0_pcmcia_driver = { ++ .driver = { ++ .name = "sa11x0-pcmcia", ++ .probe = sa11x0_drv_pcmcia_probe, ++ .remove = soc_common_drv_pcmcia_remove, ++ .suspend= pcmcia_socket_dev_suspend, ++ .resume = pcmcia_socket_dev_resume, ++ }, + }; + + /* sa11x0_pcmcia_init() +@@ -100,7 +101,7 @@ static struct device_driver sa11x0_pcmcia_driver = { + */ + static int __init sa11x0_pcmcia_init(void) + { +- return driver_register(&sa11x0_pcmcia_driver); ++ return platform_driver_register(&sa11x0_pcmcia_driver); + } + + /* sa11x0_pcmcia_exit() +@@ -110,7 +111,7 @@ static int __init sa11x0_pcmcia_init(void) + */ + static void __exit sa11x0_pcmcia_exit(void) + { +- driver_unregister(&sa11x0_pcmcia_driver); ++ platform_driver_unregister(&sa11x0_pcmcia_driver); + } + + MODULE_AUTHOR("John Dorsey "); +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 66ec5d8..aba38d7 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -123,6 +123,10 @@ config SPI_MPC52xx_PSC + This enables using the Freescale MPC52xx Programmable Serial + Controller in master SPI mode. + ++config SPI_LOCOMO ++ tristate "Locomo SPI master" ++ depends on SPI_MASTER && SHARP_LOCOMO && EXPERIMENTAL ++ + config SPI_MPC83xx + tristate "Freescale MPC83xx/QUICC Engine SPI controller" + depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 7fca043..b89992b 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o + obj-$(CONFIG_SPI_TXX9) += spi_txx9.o + obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o + obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o ++obj-$(CONFIG_SPI_LOCOMO) += locomo_spi.o + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) +diff --git a/drivers/spi/locomo_spi.c b/drivers/spi/locomo_spi.c +new file mode 100644 +index 0000000..d3a4bd9 +--- /dev/null ++++ b/drivers/spi/locomo_spi.c +@@ -0,0 +1,1097 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "locomo_spi.h" ++static struct locomospi_dev * spidev; ++static struct work_struct transfer_wq; ++int delay; ++ ++char* transtxbuf=(char*)NULL; ++char* transrxbuf=(char*)NULL; ++int transfercount=0, transfersize=0; ++static DECLARE_WAIT_QUEUE_HEAD(transferqueue); ++/* MMC_SPI functions *********************************************************/ ++ ++static int locomommcspi_init(struct device *dev, irqreturn_t (*isr)(int, void*), void *mmc) ++{ ++ int result; ++ result=request_irq(IRQ_LOCOMO_CARDDETECT, isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "locomo-spi", mmc); ++ return result; ++} ++ ++static void locomommcspi_exit(struct device *dev, void* mmc) ++{ ++ free_irq(IRQ_LOCOMO_CARDDETECT, mmc); ++} ++ ++static int locomommcspi_getro(struct device *dev) ++{ ++ return locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROT) > 0 ? 1 : 0; ++} ++ ++static void locomommcspi_setpower(struct device *dev, unsigned int mask) ++{ ++ if(!mask && spidev->card_power) ++ locomospi_power(0); ++ else if( !spidev->card_power ) ++ locomospi_power(1); ++ ++} ++ ++ ++static struct mmc_spi_platform_data colliemmc ={ ++ .init = locomommcspi_init, ++ .exit = locomommcspi_exit, ++ .detect_delay = 200, ++ .get_ro = locomommcspi_getro, ++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, ++ .setpower = locomommcspi_setpower, ++ .powerup_msecs = 200, ++}; ++ ++/* Utility function **********************************************************/ ++ ++static void locomospi_power(int on) ++{ ++ locomo_gpio_write(spidev->ldev->dev.parent, LOCOMO_GPIO_CARD_POWER, on); ++ spidev->card_power=on; ++ printk(KERN_DEBUG "locomospi: power %d\n",on); ++} ++ ++static void locomospi_setclock(unsigned int div, unsigned int clock) ++{ ++ u16 r = ioread16(spidev->base+LOCOMO_SPIMD); ++ div &= 0x7; ++ clock &= 0x3; ++ if(clock != spidev->clock_base || div != spidev->clock_div){ ++ r &= ~(LOCOMO_SPI_XSEL | LOCOMO_SPI_CLKSEL | LOCOMO_SPI_XEN); ++ iowrite16(r,spidev->base+LOCOMO_SPIMD); ++ r |= (div | (clock <<3) | LOCOMO_SPI_XEN); ++ iowrite16(r,spidev->base+LOCOMO_SPIMD); ++ spidev->clock_div = div; ++ spidev->clock_base = clock; ++ udelay(300); ++ } ++ ++} ++// returns 1 if card ist present, 0 otherwise ++static int locomospi_carddetect() ++{ ++ return (locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1; ++} ++ ++static void locomospi_setcs(int high) ++{ ++ u16 r; ++ printk(KERN_DEBUG "locomospi: cs %d\n",high); ++ r = ioread16(spidev->base + LOCOMO_SPICT); ++ if(high) ++ r |= LOCOMO_SPI_CS; ++ else ++ r &= ~LOCOMO_SPI_CS; ++ iowrite16(r, spidev->base + LOCOMO_SPICT); ++} ++ ++static void locomospi_reg_open() ++{ ++ u16 r; ++ spidev->clock_div = DIV_64; ++ spidev->clock_base = CLOCK_18MHZ; ++ locomospi_power(1); ++ msleep(100); ++// iowrite16( 0xec00 | (CLOCK_18MHZ <<3)|DIV_64, spidev->base+LOCOMO_SPIMD); ++ iowrite16( LOCOMO_SPI_MSB1ST | LOCOMO_SPI_DOSTAT | LOCOMO_SPI_RCPOL | LOCOMO_SPI_TCPOL ++ |(CLOCK_18MHZ <<3) | DIV_64, spidev->base+LOCOMO_SPIMD); ++// if(locomospi_carddetect()){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16( r, spidev->base+LOCOMO_SPIMD); ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XEN; ++ iowrite16( r, spidev->base+LOCOMO_SPIMD); ++// } ++ iowrite16( LOCOMO_SPI_CS, spidev->base+LOCOMO_SPICT); ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r |= (LOCOMO_SPI_CEN | LOCOMO_SPI_RXUEN | LOCOMO_SPI_ALIGNEN); ++ iowrite16( r, spidev->base+LOCOMO_SPICT); ++ udelay(200); ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r &= ~LOCOMO_SPI_CS; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++} ++ ++static void locomospi_reg_release() ++{ ++ u16 r; ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r &= ~LOCOMO_SPI_CEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r &= ~LOCOMO_SPI_XEN; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r &= ~LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r |= LOCOMO_SPI_XEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ locomospi_power(0); ++} ++#if 0 ++static int txrx(const char* txbuffer, char* rxbuffer, int size) ++{ ++ u16 r = ioread16(spidev->base+LOCOMO_SPICT); ++ r |= LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ printk(KERN_DEBUG "locomospi: %d bytes to prozess\n",size); ++ /* initialize global vars for isr */ ++ transfercount=0; transfersize=size; ++ transtxbuf=txbuffer; transrxbuf=rxbuffer; ++ ++ /* start transmit and go sleep isr will wake us*/ ++ enable_irq(IRQ_LOCOMO_SPI_TEND); ++ iowrite8(txbuffer[0], spidev->base+LOCOMO_SPITD); ++ wait_event(transferqueue, transfercount >= transfersize); ++ disable_irq(IRQ_LOCOMO_SPI_TEND); ++ transrxbuf=NULL; transtxbuf=NULL; ++ ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r &= ~LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ int i; ++ for(i=0; i< size; i++) ++ printk(KERN_DEBUG "locomospi: sent: %x received: %x \n",txbuffer[i], rxbuffer[i]); ++ ++ ++ return size; ++} ++ ++ ++static int tx(const char* txbuffer, int size) ++{ ++ printk(KERN_DEBUG "locomospi: %d bytes to send\n",size); ++ /* initialize global vars for isr */ ++ transfercount=0; transfersize=size; ++ transtxbuf=txbuffer; ++ ++ /* start transmit and go sleep isr will wake us*/ ++ enable_irq(IRQ_LOCOMO_SPI_RFW); ++ iowrite8(txbuffer[0], spidev->base+LOCOMO_SPITD); ++ wait_event(transferqueue, transfercount >= transfersize); ++ disable_irq(IRQ_LOCOMO_SPI_RFW); ++ transtxbuf=NULL; ++ ++ int i; ++ for(i=0; i< size; i++) ++ printk(KERN_DEBUG "locomospi: sent: %x\n",txbuffer[i]); ++ ++ ++ return size; ++} ++ ++static int rx(char* rxbuffer, int size) ++{ ++ printk(KERN_DEBUG "locomospi: %d bytes to read\n",size); ++ /* initialize global vars for isr */ ++ transfercount=0; transfersize=size; ++ transrxbuf=rxbuffer; ++ ++ /* start transmit and go sleep isr will wake us*/ ++ enable_irq(IRQ_LOCOMO_SPI_RFR); ++ rxbuffer[0]=ioread8(spidev->base+LOCOMO_SPIRD); ++ wait_event(transferqueue, transfercount >= transfersize); ++ disable_irq(IRQ_LOCOMO_SPI_RFR); ++ transrxbuf=NULL; ++ ++ int i; ++ for(i=0; i< size; i++) ++ printk(KERN_DEBUG "locomospi: received: %x \n", rxbuffer[i]); ++ ++ ++ return size; ++} ++ ++#else ++static int txrx(const char* txbuffer, char* rxbuffer, int size) ++{ ++ int i=0,j=0; ++ int wait; ++ u16 r; ++/* char * txback = kmalloc(size * sizeof(char), GFP_KERNEL); ++ memcpy(txback, txbuffer, size); ++*/ ++ if(spidev->clock_div == 4) ++ wait = 0x10000; ++ else ++ wait = 8; ++ ++// printk(KERN_DEBUG "locomospi: txrx %d bytes to prozess\n",size); ++ ++// r = ioread16(spidev->base+LOCOMO_SPICT); ++// r |= LOCOMO_SPI_ALIGNEN; ++// iowrite16(r, spidev->base+LOCOMO_SPICT); ++ //discard first bogus byte ++ ++ ioread8(spidev->base+LOCOMO_SPIRD); ++ for(i=0; ibase+LOCOMO_SPIST) & LOCOMO_SPI_RFW) ++ break; ++ } ++ iowrite8(txbuffer[i], spidev->base+LOCOMO_SPITD); ++ ndelay(delay); ++ ++ for(j=0; j <= wait; j++){ ++ if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFR) ++ break; ++ } ++ rxbuffer[i] = ioread8(spidev->base+LOCOMO_SPIRD); ++ ndelay(delay); ++ } ++// r = ioread16(spidev->base+LOCOMO_SPICT); ++// r &= ~LOCOMO_SPI_ALIGNEN; ++// iowrite16(r, spidev->base+LOCOMO_SPICT); ++ ++/* for(j=0; j< size; j++) ++ printk(KERN_DEBUG "locomospi: sent: %x received: %x \n",txback[j], rxbuffer[j]); ++ ++ kfree(txback); ++*/ return i; ++} ++ ++static int tx(const char* buffer, int size) ++{ ++ int i=0,j=0; ++ int wait; ++ u16 r; ++ if(spidev->clock_div == 4) ++ wait = 0x10000; ++ else ++ wait = 8; ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r &= ~LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ ++// printk(KERN_DEBUG "locomospi: tx %d bytes to transmit\n",size); ++ for(i=0; ibase+LOCOMO_SPIST) & LOCOMO_SPI_RFW) ++ break; ++ } ++ iowrite8(buffer[i], spidev->base+LOCOMO_SPITD); ++ ndelay(delay); ++ } ++ ++ for(j=0; j <= wait; j++){ ++ if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_TEND) ++ break; ++ } ++ ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r |= LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ ++// for(j=0; j< size; j++) ++// printk(KERN_DEBUG "locomospi: sent: %x \n", buffer[j]); ++// printk(KERN_DEBUG "locomospi: tx %d bytes transmitted\n",i); ++ return i; ++} ++ ++static int rx(char* buffer, int size) ++{ ++ int i,j; ++ int wait; ++ u16 r; ++ printk(KERN_DEBUG "locomospi: rx %d bytes to receive\n",size); ++ if(spidev->clock_div == 4) ++ wait = 0x10000; ++ else ++ wait = 8; ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r &= ~LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ ++ for(i=0; ibase+LOCOMO_SPIST) & LOCOMO_SPI_RFR) ++ break; ++ } ++ buffer[i]= ioread8(spidev->base+LOCOMO_SPIRD); ++ ndelay(delay); ++ } ++ ++ r = ioread16(spidev->base+LOCOMO_SPICT); ++ r |= LOCOMO_SPI_ALIGNEN; ++ iowrite16(r, spidev->base+LOCOMO_SPICT); ++ ++ for(j=0; j< size; j++) ++ printk(KERN_DEBUG "locomospi: received: %x \n", buffer[j]); ++ printk(KERN_DEBUG "locomospi: rx %d bytes received\n",i); ++ return i; ++} ++#endif ++/* ++static irqreturn_t locomospi_rwready(int irq, void *dev_id) ++{ ++ struct locomospi_dev* dev=(struct locomospi_dev*) dev_id; ++// dev_dbg(&spidev->sdev->dev, "IRQ: %d\n", irq); ++// printk(KERN_DEBUG "locomospi: IRQ: %d\n", irq); ++ wake_up_interruptible(&dev->waitqueue); ++ return IRQ_HANDLED; ++} ++*/ ++static irqreturn_t locomospi_testisr(int irq, void *dev_id) ++{ ++ char *buf=""; ++ switch(irq){ ++ case IRQ_LOCOMO_SPI_RFR: buf="RFR"; ++ break; ++ case IRQ_LOCOMO_SPI_RFW: buf="RFW"; ++ break; ++ case IRQ_LOCOMO_SPI_REND:buf="REND"; ++ break; ++ case IRQ_LOCOMO_SPI_TEND:buf="TEND"; ++ break; ++ case IRQ_LOCOMO_CARDDETECT: ++ buf="CARD_DETECT"; ++ break; ++ default: return IRQ_NONE; ++ } ++ printk(KERN_DEBUG "locomospi: IRQ: %s\n",buf); ++// dev_dbg(&spidev->sdev->dev, "IRQ: %s\n",buf); ++ return IRQ_HANDLED; ++} ++static irqreturn_t locomospi_txrxisr(int irq, void *dev_id) ++{ ++ if(transfercount < transfersize){ ++ transrxbuf[transfercount++] = ioread8(spidev->base+LOCOMO_SPIRD); ++ iowrite8(transtxbuf[transfercount], spidev->base+LOCOMO_SPITD); ++ } ++ else{ ++ /* transfer complete. wake up txrx */ ++ wake_up(&transferqueue); ++ } ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t locomospi_txisr(int irq, void *dev_id) ++{ ++ if(transfercount < transfersize){ ++ iowrite8(transtxbuf[transfercount++], spidev->base+LOCOMO_SPITD); ++ } ++ else{ ++ /* transfer complete. wake up txrx */ ++ wake_up(&transferqueue); ++ } ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t locomospi_rxisr(int irq, void *dev_id) ++{ ++ if(transfercount < transfersize){ ++ transrxbuf[transfercount++] = ioread8(spidev->base+LOCOMO_SPIRD); ++ } ++ else{ ++ /* transfer complete. wake up txrx */ ++ wake_up(&transferqueue); ++ } ++ return IRQ_HANDLED; ++} ++ ++static void locomospi_clock(unsigned int Hz) ++{ ++ u16 r; ++ printk(KERN_DEBUG "locomospi: changing clock to: %d\n", Hz); ++ if(Hz == 0){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r &= ~LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ } ++ else if(Hz >= 24576000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_1, CLOCK_25MHZ); ++ delay=41; ++ } ++ else if(Hz >= 22579200){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_1, CLOCK_22MHZ); ++ delay=45; ++ } ++ else if(Hz >= 18432000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_1, CLOCK_18MHZ); ++ delay=55; ++ } ++ else if(Hz >= 12288000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_2, CLOCK_25MHZ); ++ delay=82; ++ } ++ else if(Hz >= 11289600){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_2, CLOCK_22MHZ); ++ delay=89; ++ } ++ else if(Hz >= 9216000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_2, CLOCK_18MHZ); ++ delay=110; ++ } ++ else if(Hz >= 6144000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_4, CLOCK_25MHZ); ++ delay=164; ++ } ++ else if(Hz >= 5644800){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_4, CLOCK_22MHZ); ++ delay=178; ++ } ++ else if(Hz >= 4608000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_4, CLOCK_18MHZ); ++ delay=218; ++ } ++ else if(Hz >= 3072000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_8, CLOCK_25MHZ); ++ delay=327; ++ } ++ else if(Hz >= 2822400){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_8, CLOCK_22MHZ); ++ delay=355; ++ } ++ else if(Hz >= 2304000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_8, CLOCK_18MHZ); ++ delay=435; ++ } ++ else if(Hz >= 384000){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_64, CLOCK_25MHZ); ++ delay=2605; ++ } ++ else if(Hz >= 352800){ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_64, CLOCK_22MHZ); ++ delay=2834; ++ } ++ else{ /* set to 288 KHz */ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_XON; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ locomospi_setclock(DIV_64, CLOCK_18MHZ); ++ delay=3473; ++ } ++ spidev->clock = Hz; ++} ++ ++/* sysfs attributes used for debug *******************************************/ ++ ++/* SPI registers */ ++ssize_t locomospi_showspimd(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIMD)); ++} ++ ++ssize_t locomospi_storespimd(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIMD); ++ return count; ++} ++static DRIVER_ATTR(spimd, S_IWUSR | S_IRUGO, locomospi_showspimd, locomospi_storespimd); ++ ++ssize_t locomospi_showspict(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPICT)); ++} ++ ++ssize_t locomospi_storespict(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPICT); ++ return count; ++} ++static DRIVER_ATTR(spict, S_IWUSR | S_IRUGO, locomospi_showspict, locomospi_storespict); ++ ++ssize_t locomospi_showspist(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIST)); ++} ++ ++ssize_t locomospi_storespist(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIST); ++ return count; ++} ++static DRIVER_ATTR(spist, S_IWUSR | S_IRUGO, locomospi_showspist, locomospi_storespist); ++ ++ssize_t locomospi_showspitd(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPITD)); ++} ++ ++ssize_t locomospi_storespitd(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITD); ++ return count; ++} ++static DRIVER_ATTR(spitd, S_IWUSR | S_IRUGO, locomospi_showspitd, locomospi_storespitd); ++ ++ssize_t locomospi_showspird(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIRD)); ++} ++ ++ssize_t locomospi_storespird(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRD); ++ return count; ++} ++static DRIVER_ATTR(spird, S_IWUSR | S_IRUGO, locomospi_showspird, locomospi_storespird); ++ ++ssize_t locomospi_showspits(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPITS)); ++} ++ ++ssize_t locomospi_storespits(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITS); ++ return count; ++} ++static DRIVER_ATTR(spits, S_IWUSR | S_IRUGO, locomospi_showspits, locomospi_storespits); ++ ++ssize_t locomospi_showspirs(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIRS)); ++} ++ ++ssize_t locomospi_storespirs(struct device_driver *drv, const char *buf, size_t count) ++{ ++ iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRS); ++ return count; ++} ++static DRIVER_ATTR(spirs, S_IWUSR | S_IRUGO, locomospi_showspirs, locomospi_storespirs); ++ ++/* MMC Card status */ ++ ++ssize_t locomospi_showpower(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", spidev->card_power); ++} ++ ++ssize_t locomospi_storepower(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomospi_power(simple_strtoul(buf, NULL, 10)); ++ return count; ++} ++static DRIVER_ATTR(cardpower, S_IWUSR | S_IRUGO, locomospi_showpower, locomospi_storepower); ++ ++ssize_t locomospi_detectcard(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1); ++} ++static DRIVER_ATTR(carddetect, S_IRUGO, locomospi_detectcard, NULL); ++ ++ssize_t locomospi_writeprotect(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROT)>0)?1:0); ++} ++static DRIVER_ATTR(cardwriteprotect, S_IRUGO, locomospi_writeprotect, NULL); ++ ++ ++ssize_t locomospi_showclock(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", spidev->clock); ++} ++ ++ssize_t locomospi_storeclock(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomospi_clock(simple_strtoul(buf, NULL, 10)); ++ return count; ++} ++static DRIVER_ATTR(clock, S_IWUSR | S_IRUGO, locomospi_showclock, locomospi_storeclock); ++ ++/* debug */ ++ssize_t locomospi_showdelay(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", delay); ++} ++ ++ssize_t locomospi_storedelay(struct device_driver *drv, const char *buf, size_t count) ++{ ++ delay=simple_strtoul(buf,NULL,10); ++ return count; ++} ++static DRIVER_ATTR(delay, S_IWUSR | S_IRUGO, locomospi_showdelay, locomospi_storedelay); ++ ++ssize_t locomospi_reset(struct device_driver *drv, const char *buf, size_t count) ++{ ++ int choice = simple_strtoul(buf, NULL, 10); ++ char buff[100]; ++ u16 r; ++ switch(choice){ ++ case 0: locomospi_reg_release(); ++ schedule_timeout(2*HZ); ++ locomospi_reg_open(); ++ break; ++ case 1: { ++ char b1[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; ++ char b2[] = "\xff\x40\x00\x00\x00\x00\x95\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; ++ locomospi_setcs(1); ++ txrx(b1,b1,17); ++ locomospi_setcs(0); ++ txrx(b2,b2,18); ++ ++ } ++ break; ++ case 2: locomospi_setcs(1); ++ txrx("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",buff,18); ++ locomospi_setcs(0); ++ txrx("\xff\x40\x00\x00\x00\x00\x95\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",buff,17); ++ break; ++ case 3: ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r |= LOCOMO_SPI_LOOPBACK; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ txrx("X",buff,1); ++ txrx("abcdefghijklmnopqrstuvwxyz1234567890",buff,36); ++ txrx("Y",buff,1); ++ udelay(100); ++ txrx("Z",buff,1); ++ schedule_timeout(HZ); ++ txrx("abcdefghijklmnopqrstuvwxyz1234567890",buff,36); ++ ++ r = ioread16(spidev->base+LOCOMO_SPIMD); ++ r &= ~LOCOMO_SPI_LOOPBACK; ++ iowrite16(r, spidev->base+LOCOMO_SPIMD); ++ break; ++ default: /* do nothing */; ++ } ++ return count; ++} ++static DRIVER_ATTR(reset, S_IWUSR, NULL, locomospi_reset); ++ ++typedef struct locomo_reg_entry { ++ u32 addr; ++ char* name; ++} locomo_reg_entry_t; ++#define LCM (sizeof(locomo_regs)/sizeof(locomo_reg_entry_t)) ++static locomo_reg_entry_t locomo_regs[] = ++{ ++/* { addr, name, description } */ ++ { 0x00, "VER" }, ++ { 0x04, "ST" }, ++ { 0x08, "C32K" }, ++ { 0x0C, "ICR" }, ++ { 0x10, "MCSX0" }, ++ { 0x14, "MCSX1" }, ++ { 0x18, "MCSX2" }, ++ { 0x1C, "MCSX3" }, ++ { 0x20, "ASD" }, ++ { 0x28, "HSD" }, ++ { 0x2C, "HSC" }, ++ { 0x30, "TADC" }, ++ { 0x38, "TC" }, ++ { 0x3C, "CPSD" }, ++ { 0x40, "KIB" }, ++ { 0x44, "KSC" }, ++ { 0x48, "KCMD" }, ++ { 0x4C, "KIC" }, ++ { 0x54, "ACC" }, ++ { 0x60, "SPIMD" }, ++ { 0x64, "SPICT" }, ++ { 0x68, "SPIST" }, ++ { 0x70, "SPIIS" }, ++ { 0x74, "SPIWE" }, ++ { 0x78, "SPIIE" }, ++ { 0x7C, "SPIIR" }, ++ { 0x80, "SPITD" }, ++ { 0x84, "SPIRD" }, ++ { 0x88, "SPITS" }, ++ { 0x8C, "SPIRS" }, ++ { 0x90, "GPD" }, ++ { 0x94, "GPE" }, ++ { 0x98, "GPL" }, ++ { 0x9C, "GPO" }, ++ { 0xa0, "GRIE" }, ++ { 0xa4, "GFIE" }, ++ { 0xa8, "GIS" }, ++ { 0xac, "GWE" }, ++ { 0xb0, "GIE" }, ++ { 0xb4, "GIR" }, ++ { 0xc8, "ALC" }, ++ { 0xcc, "ALR" }, ++ { 0xd0, "PAIF" }, ++ { 0xd8, "LTC" }, ++ { 0xdc, "LTINT" }, ++ { 0xe0, "DAC" }, ++ { 0xe8, "LPT0" }, ++ { 0xec, "LPT1" }, ++ { 0xfc, "TCR" }, ++}; ++ ++static ssize_t lcm_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int base = spidev->base - LOCOMO_SPI; ++ char b[4000]=""; ++ char c[30]; ++ int i; ++ for(i=0; imessage_list){ ++ msg = list_entry(mptr, struct spi_message, queue); ++ ++ msg->status = 0; ++ msg->actual_length = 0; ++ list_for_each(tptr, &msg->transfers){ ++ entry = list_entry(tptr, struct spi_transfer, transfer_list); ++ if(entry->tx_buf && entry->rx_buf){ //duplex ++ txrx((char*) entry->tx_buf, (char*) entry->rx_buf, entry->len); ++ msg->actual_length += entry->len; ++ } else if(entry->tx_buf && !entry->rx_buf){ //write ++ tx((char*) entry->tx_buf, entry->len); ++ msg->actual_length += entry->len; ++ } else if(!entry->tx_buf && entry->rx_buf){ //read ++ rx((char*) entry->rx_buf, entry->len); ++ msg->actual_length += entry->len; ++ } else if(!entry->tx_buf && !entry->rx_buf){ //error ++ dev_err(&spidev->sdev->dev, "do_transfer: no buffers allocated\n"); ++ msg->status = -EFAULT; ++ } ++ } ++ spin_lock(&spidev->message_lock); ++ list_del(mptr); ++ spin_unlock(&spidev->message_lock); ++ msg->complete(msg->context); ++ } ++} ++ ++static int locomospi_setup(struct spi_device *spi) ++{ ++ if((spi->mode & SPI_CS_HIGH) != (spidev->spimode & SPI_CS_HIGH)) ++ locomospi_setcs(spi->mode & SPI_CS_HIGH ? 1 : 0 ); ++ if(spidev->clock != spi->max_speed_hz){ ++ locomospi_clock(spi->max_speed_hz); ++ } ++ spidev->spimode = spi->mode; ++ ++ return 0; ++} ++ ++static int locomospi_transfer(struct spi_device *spi, struct spi_message *msg) ++{ ++ ++ spin_lock(&spidev->message_lock); ++ list_add_tail(&msg->queue, &spidev->message_list); ++ spin_unlock(&spidev->message_lock); ++ schedule_work(&transfer_wq); ++ return 0; ++} ++ ++static struct locomo_driver locomo_spi_driver = { ++ .drv = { ++ .name = "locomo-spi", ++ }, ++ .devid = LOCOMO_DEVID_SPI, ++ .probe = locomospi_probe, ++ .remove = locomospi_remove, ++#ifdef CONFIG_PM ++ .suspend = locomospi_suspend, ++ .resume = locomospi_resume, ++#endif ++}; ++ ++static struct spi_board_info board = { ++ .modalias = "mmc_spi", ++ .platform_data = (void*) &colliemmc, ++ .controller_data= NULL, ++ .irq = 0, ++ .max_speed_hz = 25000000, ++ .bus_num = 0, ++ .chip_select = 0, ++ .mode = 0, ++}; ++ ++#ifdef CONFIG_PM ++static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state) ++{ ++ disable_irq(IRQ_LOCOMO_CARDDETECT); ++ return 0; ++} ++ ++static int locomospi_resume(struct locomo_dev *dev) ++{ ++ enable_irq(IRQ_LOCOMO_CARDDETECT); ++ return 0; ++} ++#endif ++ ++static int locomospi_probe(struct locomo_dev *dev) ++{ ++ int result=0; ++ printk(KERN_DEBUG "Collie MMC over SPI Driver\n"); ++ spidev=kmalloc(sizeof(struct locomospi_dev),GFP_KERNEL); ++ if(!spidev){ ++ return -ENOMEM; ++ } ++ spidev->ldev = dev; ++ spidev->card_power = 1; ++ spidev->spimode = 0; ++ ++ if(!request_mem_region((unsigned long) dev->mapbase, dev->length, LOCOMO_DRIVER_NAME(dev))) { ++ dev_err(&dev->dev, " Can't aquire access to io memory\n"); ++ return -EBUSY; ++ } ++ spidev->base=(unsigned long) dev->mapbase; ++ locomospi_reg_open(); ++ ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_POWER, 0); ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_DETECT, 1); ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_WRITE_PROT, 1); ++ ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardpower); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_carddetect); ++ if(result){ ++ dev_err(&dev->dev,"error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardwriteprotect); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spimd); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spict); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spist); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spitd); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spird); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spits); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spirs); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_clock); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_delay); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_reset); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_regs); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ INIT_WORK(&transfer_wq, locomospi_do_transfer); ++ INIT_LIST_HEAD(&spidev->message_list); ++ spin_lock_init(&spidev->message_lock); ++ init_waitqueue_head(&spidev->waitqueue); ++ spidev->master=spi_alloc_master(&dev->dev,0); ++ if(!spidev->master){ ++ result=-ENOMEM; ++ goto region; ++ } ++ spidev->master->bus_num = 0; ++ spidev->master->num_chipselect = 1; ++ spidev->master->setup = locomospi_setup; ++ spidev->master->transfer = locomospi_transfer; ++ spidev->sdev = spi_new_device(spidev->master, &board); ++ if(!spidev->sdev){ ++ dev_err(&dev->dev, "failed to register spi device\n"); ++ result = -EINVAL; ++ goto master; ++ } ++/* result=request_irq(IRQ_LOCOMO_SPI_RFR, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: RFR\n"); ++ goto regdev; ++ } ++ //disable_irq(IRQ_LOCOMO_SPI_RFR); ++*//* result=request_irq(IRQ_LOCOMO_SPI_RFW, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: RFW\n"); ++ goto irq1; ++ } ++ //disable_irq(IRQ_LOCOMO_SPI_RFW); ++*//* result=request_irq(IRQ_LOCOMO_SPI_REND, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: REND\n"); ++ goto irq2; ++ } ++*//* result=request_irq(IRQ_LOCOMO_SPI_TEND, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: TEND\n"); ++ goto irq3; ++ } ++ //disable_irq(IRQ_LOCOMO_SPI_TEND); ++*/ spidev->workqueue = create_singlethread_workqueue("locomo-spi"); ++ if(!spidev->workqueue){ ++ dev_err(&dev->dev, "failed to create workqueue\n"); ++ goto irq4; ++ } ++ result=spi_register_master(spidev->master); ++ if(result){ ++ dev_err(&dev->dev, "faile