diff options
Diffstat (limited to 'packages/linux/linux-rp-2.6.26/collie.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.26/collie.patch | 2601 |
1 files changed, 0 insertions, 2601 deletions
diff --git a/packages/linux/linux-rp-2.6.26/collie.patch b/packages/linux/linux-rp-2.6.26/collie.patch deleted file mode 100644 index 750be8ecf3..0000000000 --- a/packages/linux/linux-rp-2.6.26/collie.patch +++ /dev/null @@ -1,2601 +0,0 @@ -Index: linux-2.6.26/arch/arm/Kconfig -=================================================================== ---- linux-2.6.26.orig/arch/arm/Kconfig 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/arch/arm/Kconfig 2008-10-17 18:15:31.391792839 +0200 -@@ -967,7 +967,7 @@ - - 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 -Index: linux-2.6.26/arch/arm/mach-sa1100/collie.c -=================================================================== ---- linux-2.6.26.orig/arch/arm/mach-sa1100/collie.c 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/arch/arm/mach-sa1100/collie.c 2008-10-17 18:15:31.391792839 +0200 -@@ -206,7 +206,7 @@ - } - - static struct flash_platform_data collie_flash_data = { -- .map_name = "cfi_probe", -+ .map_name = "sharp", - .set_vpp = collie_set_vpp, - .parts = collie_partitions, - .nr_parts = ARRAY_SIZE(collie_partitions), -Index: linux-2.6.26/arch/arm/mach-sa1100/dma.c -=================================================================== ---- linux-2.6.26.orig/arch/arm/mach-sa1100/dma.c 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/arch/arm/mach-sa1100/dma.c 2008-10-17 18:15:31.399789199 +0200 -@@ -39,7 +39,7 @@ - - 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) -Index: linux-2.6.26/drivers/input/keyboard/locomokbd.c -=================================================================== ---- linux-2.6.26.orig/drivers/input/keyboard/locomokbd.c 2008-10-17 18:13:16.000000000 +0200 -+++ linux-2.6.26/drivers/input/keyboard/locomokbd.c 2008-10-17 18:15:31.403791239 +0200 -@@ -272,6 +272,7 @@ - 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); -Index: linux-2.6.26/drivers/mfd/Kconfig -=================================================================== ---- linux-2.6.26.orig/drivers/mfd/Kconfig 2008-10-17 18:13:21.000000000 +0200 -+++ linux-2.6.26/drivers/mfd/Kconfig 2008-10-17 18:15:31.403791239 +0200 -@@ -77,4 +77,10 @@ - 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 -Index: linux-2.6.26/drivers/mfd/Makefile -=================================================================== ---- linux-2.6.26.orig/drivers/mfd/Makefile 2008-10-17 18:13:21.000000000 +0200 -+++ linux-2.6.26/drivers/mfd/Makefile 2008-10-17 18:15:31.407791679 +0200 -@@ -14,7 +14,7 @@ - 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 -Index: linux-2.6.26/drivers/mfd/collie-ts.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.26/drivers/mfd/collie-ts.c 2008-10-17 18:15:31.415790559 +0200 -@@ -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 <jco@ict.es> : -+ * -+ * 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 <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/smp.h> -+#include <linux/smp_lock.h> -+#include <linux/sched.h> -+#include <linux/completion.h> -+#include <linux/delay.h> -+#include <linux/string.h> -+#include <linux/input.h> -+#include <linux/device.h> -+#include <linux/freezer.h> -+#include <linux/slab.h> -+#include <linux/kthread.h> -+#include <linux/semaphore.h> -+ -+#include <asm/dma.h> -+#include <asm/arch/collie.h> -+#include <asm/mach-types.h> -+ -+#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 <rmk@arm.linux.org.uk>"); -+MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.26/drivers/mfd/ucb1x00.h -=================================================================== ---- linux-2.6.26.orig/drivers/mfd/ucb1x00.h 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/mfd/ucb1x00.h 2008-10-17 18:15:31.415790559 +0200 -@@ -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 */ -Index: linux-2.6.26/drivers/mtd/chips/Kconfig -=================================================================== ---- linux-2.6.26.orig/drivers/mtd/chips/Kconfig 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/mtd/chips/Kconfig 2008-10-17 18:15:31.419791479 +0200 -@@ -239,5 +239,13 @@ - used for XIP purposes. If you're not sure what this is all about - then say N. - -+config MTD_SHARP -+ tristate "pre-CFI Sharp chip support" -+ depends on MTD -+ help -+ This option enables support for flash chips using Sharp-compatible -+ commands, including some which are not CFI-compatible and hence -+ cannot be used with the CONFIG_MTD_CFI_INTELxxx options. -+ - endmenu - -Index: linux-2.6.26/drivers/mtd/chips/Makefile -=================================================================== ---- linux-2.6.26.orig/drivers/mtd/chips/Makefile 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/mtd/chips/Makefile 2008-10-17 18:15:31.419791479 +0200 -@@ -12,4 +12,5 @@ - obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o - obj-$(CONFIG_MTD_RAM) += map_ram.o - obj-$(CONFIG_MTD_ROM) += map_rom.o -+obj-$(CONFIG_MTD_SHARP) += sharp.o - obj-$(CONFIG_MTD_ABSENT) += map_absent.o -Index: linux-2.6.26/drivers/mtd/chips/sharp.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.26/drivers/mtd/chips/sharp.c 2008-10-17 18:15:31.423790399 +0200 -@@ -0,0 +1,645 @@ -+/* -+ * MTD chip driver for pre-CFI Sharp flash chips -+ * -+ * Copyright 2000,2001 David A. Schleef <ds@schleef.org> -+ * 2000,2001 Lineo, Inc. -+ * -+ * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $ -+ * -+ * Devices supported: -+ * LH28F016SCT Symmetrical block flash memory, 2Mx8 -+ * LH28F008SCT Symmetrical block flash memory, 1Mx8 -+ * -+ * Documentation: -+ * http://www.sharpmeg.com/datasheets/memic/flashcmp/ -+ * http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf -+ * 016sctl9.pdf -+ * -+ * Limitations: -+ * This driver only supports 4x1 arrangement of chips. -+ * Not tested on anything but PowerPC. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/sched.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/cfi.h> -+#include <linux/delay.h> -+#include <linux/init.h> -+ -+#define CMD_RESET 0xffffffff -+#define CMD_READ_ID 0x90909090 -+#define CMD_READ_STATUS 0x70707070 -+#define CMD_CLEAR_STATUS 0x50505050 -+#define CMD_BLOCK_ERASE_1 0x20202020 -+#define CMD_BLOCK_ERASE_2 0xd0d0d0d0 -+#define CMD_BYTE_WRITE 0x40404040 -+#define CMD_SUSPEND 0xb0b0b0b0 -+#define CMD_RESUME 0xd0d0d0d0 -+#define CMD_SET_BLOCK_LOCK_1 0x60606060 -+#define CMD_SET_BLOCK_LOCK_2 0x01010101 -+#define CMD_SET_MASTER_LOCK_1 0x60606060 -+#define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1 -+#define CMD_CLEAR_BLOCK_LOCKS_1 0x60606060 -+#define CMD_CLEAR_BLOCK_LOCKS_2 0xd0d0d0d0 -+ -+#define SR_READY 0x80808080 // 1 = ready -+#define SR_ERASE_SUSPEND 0x40404040 // 1 = block erase suspended -+#define SR_ERROR_ERASE 0x20202020 // 1 = error in block erase or clear lock bits -+#define SR_ERROR_WRITE 0x10101010 // 1 = error in byte write or set lock bit -+#define SR_VPP 0x08080808 // 1 = Vpp is low -+#define SR_WRITE_SUSPEND 0x04040404 // 1 = byte write suspended -+#define SR_PROTECT 0x02020202 // 1 = lock bit set -+#define SR_RESERVED 0x01010101 -+ -+#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT) -+ -+#define BLOCK_MASK 0xfffe0000 -+ -+/* Configuration options */ -+ -+#define AUTOUNLOCK /* automatically unlocks blocks before erasing */ -+ -+static struct mtd_info *sharp_probe(struct map_info *); -+ -+static int sharp_probe_map(struct map_info *map, struct mtd_info *mtd); -+ -+static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf); -+static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, const u_char *buf); -+static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr); -+static void sharp_sync(struct mtd_info *mtd); -+static int sharp_suspend(struct mtd_info *mtd); -+static void sharp_resume(struct mtd_info *mtd); -+static void sharp_destroy(struct mtd_info *mtd); -+ -+static int sharp_write_oneword(struct map_info *map, struct flchip *chip, -+ unsigned long adr, __u32 datum); -+static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, -+ unsigned long adr); -+#ifdef AUTOUNLOCK -+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, -+ unsigned long adr); -+#endif -+ -+ -+struct sharp_info{ -+ struct flchip *chip; -+ int bogus; -+ int chipshift; -+ int numchips; -+ struct flchip chips[1]; -+}; -+ -+static void sharp_destroy(struct mtd_info *mtd); -+ -+static struct mtd_chip_driver sharp_chipdrv = { -+ .probe = sharp_probe, -+ .destroy = sharp_destroy, -+ .name = "sharp", -+ .module = THIS_MODULE -+}; -+ -+static void sharp_udelay(unsigned long i) { -+ if (in_interrupt()) { -+ udelay(i); -+ } else { -+ schedule(); -+ } -+} -+ -+static struct mtd_info *sharp_probe(struct map_info *map) -+{ -+ struct mtd_info *mtd = NULL; -+ struct sharp_info *sharp = NULL; -+ int width; -+ -+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); -+ if(!mtd) -+ return NULL; -+ -+ sharp = kzalloc(sizeof(*sharp), GFP_KERNEL); -+ if(!sharp) { -+ kfree(mtd); -+ return NULL; -+ } -+ -+ width = sharp_probe_map(map,mtd); -+ if(!width){ -+ kfree(mtd); -+ kfree(sharp); -+ return NULL; -+ } -+ -+ mtd->priv = map; -+ mtd->type = MTD_NORFLASH; -+ mtd->erase = sharp_erase; -+ mtd->read = sharp_read; -+ mtd->write = sharp_write; -+ mtd->sync = sharp_sync; -+ mtd->suspend = sharp_suspend; -+ mtd->resume = sharp_resume; -+ mtd->flags = MTD_CAP_NORFLASH; -+ mtd->writesize = 1; -+ mtd->name = map->name; -+ -+ sharp->chipshift = 24; -+ sharp->numchips = 1; -+ sharp->chips[0].start = 0; -+ sharp->chips[0].state = FL_READY; -+ sharp->chips[0].mutex = &sharp->chips[0]._spinlock; -+ sharp->chips[0].word_write_time = 0; -+ init_waitqueue_head(&sharp->chips[0].wq); -+ spin_lock_init(&sharp->chips[0]._spinlock); -+ -+ map->fldrv = &sharp_chipdrv; -+ map->fldrv_priv = sharp; -+ -+ __module_get(THIS_MODULE); -+ return mtd; -+} -+ -+static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr) -+{ -+ map_word map_cmd; -+ map_cmd.x[0] = cmd; -+ map_write(map, map_cmd, adr); -+} -+ -+static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) -+{ -+ map_word tmp, read0, read4; -+ unsigned long base = 0; -+ int width = 4; -+ -+ tmp = map_read(map, base+0); -+ -+ sharp_send_cmd(map, CMD_READ_ID, base+0); -+ -+ read0 = map_read(map, base+0); -+ read4 = map_read(map, base+4); -+ if (read0.x[0] == 0x00b000b0) { -+ printk("Sharp chip, %lx, %lx, width = %d\n", read0.x[0], read4.x[0], width); -+ /* Prints b000b0, b000b0, width = 4 on collie */ -+ switch(read4.x[0]){ -+ case 0xaaaaaaaa: -+ case 0xa0a0a0a0: -+ /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/ -+ /* a0 - LH28F016SCT-Z4 2Mx8, 32 64k blocks*/ -+ mtd->erasesize = 0x10000 * width; -+ mtd->size = 0x200000 * width; -+ return width; -+ case 0xa6a6a6a6: -+ /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/ -+ /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/ -+ mtd->erasesize = 0x10000 * width; -+ mtd->size = 0x100000 * width; -+ return width; -+ case 0x00b000b0: -+ /* a6 - LH28F640BFHE 8 64k * 2 chip blocks*/ -+ mtd->erasesize = 0x10000 * width / 2; -+ mtd->size = 0x800000 * width / 2; -+ return width; -+ default: -+ printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n", -+ read0.x[0], read4.x[0]); -+ } -+ } else if ((map_read(map, base+0).x[0] == CMD_READ_ID)){ -+ /* RAM, probably */ -+ printk("Looks like RAM\n"); -+ map_write(map, tmp, base+0); -+ }else{ -+ printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n", -+ read0.x[0], read4.x[0]); -+ } -+ -+ return 0; -+} -+ -+/* This function returns with the chip->mutex lock held. */ -+static int sharp_wait(struct map_info *map, struct flchip *chip) -+{ -+ map_word status; -+ unsigned long timeo = jiffies + HZ; -+ DECLARE_WAITQUEUE(wait, current); -+ int adr = 0; -+ -+retry: -+ spin_lock_bh(chip->mutex); -+ -+ switch (chip->state) { -+ case FL_READY: -+ sharp_send_cmd(map, CMD_READ_STATUS, adr); -+ chip->state = FL_STATUS; -+ case FL_STATUS: -+ status = map_read(map, adr); -+ if ((status.x[0] & SR_READY) == SR_READY) -+ break; -+ spin_unlock_bh(chip->mutex); -+ if (time_after(jiffies, timeo)) { -+ printk("Waiting for chip to be ready timed out in erase\n"); -+ return -EIO; -+ } -+ sharp_udelay(1); -+ goto retry; -+ default: -+ set_current_state(TASK_INTERRUPTIBLE); -+ add_wait_queue(&chip->wq, &wait); -+ -+ spin_unlock_bh(chip->mutex); -+ -+ sharp_udelay(1); -+ -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&chip->wq, &wait); -+ -+ if(signal_pending(current)) -+ return -EINTR; -+ -+ timeo = jiffies + HZ; -+ -+ goto retry; -+ } -+ -+ sharp_send_cmd(map, CMD_RESET, adr); -+ -+ chip->state = FL_READY; -+ -+ return 0; -+} -+ -+static void sharp_release(struct flchip *chip) -+{ -+ wake_up(&chip->wq); -+ spin_unlock_bh(chip->mutex); -+} -+ -+static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ int chipnum; -+ int ret = 0; -+ int ofs = 0; -+ -+ chipnum = (from >> sharp->chipshift); -+ ofs = from & ((1 << sharp->chipshift)-1); -+ -+ *retlen = 0; -+ -+ while(len){ -+ unsigned long thislen; -+ -+ if(chipnum>=sharp->numchips) -+ break; -+ -+ thislen = len; -+ if(ofs+thislen >= (1<<sharp->chipshift)) -+ thislen = (1<<sharp->chipshift) - ofs; -+ -+ ret = sharp_wait(map,&sharp->chips[chipnum]); -+ if(ret<0) -+ break; -+ -+ map_copy_from(map,buf,ofs,thislen); -+ -+ sharp_release(&sharp->chips[chipnum]); -+ -+ *retlen += thislen; -+ len -= thislen; -+ buf += thislen; -+ -+ ofs = 0; -+ chipnum++; -+ } -+ return ret; -+} -+ -+static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ int ret = 0; -+ int i,j; -+ int chipnum; -+ unsigned long ofs; -+ union { u32 l; unsigned char uc[4]; } tbuf; -+ -+ *retlen = 0; -+ -+ while(len){ -+ tbuf.l = 0xffffffff; -+ chipnum = to >> sharp->chipshift; -+ ofs = to & ((1<<sharp->chipshift)-1); -+ -+ j=0; -+ for(i=ofs&3;i<4 && len;i++){ -+ tbuf.uc[i] = *buf; -+ buf++; -+ to++; -+ len--; -+ j++; -+ } -+ sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l); -+ if(ret<0) -+ return ret; -+ (*retlen)+=j; -+ } -+ -+ return 0; -+} -+ -+static int sharp_write_oneword(struct map_info *map, struct flchip *chip, -+ unsigned long adr, __u32 datum) -+{ -+ int ret; -+ int try; -+ int i; -+ map_word data, status; -+ -+ status.x[0] = 0; -+ ret = sharp_wait(map,chip); -+ if (ret < 0) -+ return ret; -+ -+ for (try=0; try<10; try++) { -+ long timeo; -+ -+ sharp_send_cmd(map, CMD_BYTE_WRITE, adr); -+ /* cpu_to_le32 -> hack to fix the writel be->le conversion */ -+ data.x[0] = cpu_to_le32(datum); -+ map_write(map, data, adr); -+ -+ chip->state = FL_WRITING; -+ timeo = jiffies + (HZ/2); -+ -+ sharp_send_cmd(map, CMD_READ_STATUS, adr); -+ for(i=0;i<100;i++){ -+ status = map_read(map, adr); -+ if((status.x[0] & SR_READY) == SR_READY) -+ break; -+ } -+#ifdef AUTOUNLOCK -+ if (status.x[0] & SR_PROTECT) { /* lock block */ -+ sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -+ sharp_unlock_oneblock(map,chip,adr); -+ sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -+ sharp_send_cmd(map, CMD_RESET, adr); -+ continue; -+ } -+#endif -+ if(i==100){ -+ printk("sharp: timed out writing\n"); -+ } -+ -+ if (!(status.x[0] & SR_ERRORS)) -+ break; -+ -+ printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]); -+ -+ sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -+ } -+ sharp_send_cmd(map, CMD_RESET, adr); -+ chip->state = FL_READY; -+ -+ sharp_release(chip); -+ -+ return 0; -+} -+ -+static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ unsigned long adr,len; -+ int chipnum, ret=0; -+ -+ if(instr->addr & (mtd->erasesize - 1)) -+ return -EINVAL; -+ if(instr->len & (mtd->erasesize - 1)) -+ return -EINVAL; -+ if(instr->len + instr->addr > mtd->size) -+ return -EINVAL; -+ -+ chipnum = instr->addr >> sharp->chipshift; -+ adr = instr->addr & ((1<<sharp->chipshift)-1); -+ len = instr->len; -+ -+ while(len){ -+ ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr); -+ if(ret)return ret; -+ -+ if (adr >= 0xfe0000) { -+ adr += mtd->erasesize / 8; -+ len -= mtd->erasesize / 8; -+ } else { -+ adr += mtd->erasesize; -+ len -= mtd->erasesize; -+ } -+ if(adr >> sharp->chipshift){ -+ adr = 0; -+ chipnum++; -+ if(chipnum>=sharp->numchips) -+ break; -+ } -+ } -+ -+ instr->state = MTD_ERASE_DONE; -+ mtd_erase_callback(instr); -+ -+ return 0; -+} -+ -+static inline int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, -+ unsigned long adr) -+{ -+ int ret; -+ unsigned long timeo; -+ map_word status; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ sharp_send_cmd(map, CMD_READ_STATUS, adr); -+ status = map_read(map, adr); -+ -+ timeo = jiffies + HZ * 10; -+ -+ while (time_before(jiffies, timeo)) { -+ sharp_send_cmd(map, CMD_READ_STATUS, adr); -+ status = map_read(map, adr); -+ if ((status.x[0] & SR_READY) == SR_READY) { -+ ret = 0; -+ goto out; -+ } -+ set_current_state(TASK_INTERRUPTIBLE); -+ add_wait_queue(&chip->wq, &wait); -+ -+ spin_unlock_bh(chip->mutex); -+ -+ schedule_timeout(1); -+ schedule(); -+ -+ spin_lock_bh(chip->mutex); -+ -+ remove_wait_queue(&chip->wq, &wait); -+ set_current_state(TASK_RUNNING); -+ } -+ ret = -ETIME; -+out: -+ return ret; -+} -+ -+static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, -+ unsigned long adr) -+{ -+ int ret; -+ map_word status; -+ -+ ret = sharp_wait(map,chip); -+ if (ret < 0) -+ return ret; -+ -+#ifdef AUTOUNLOCK -+ /* This seems like a good place to do an unlock */ -+ sharp_unlock_oneblock(map,chip,adr); -+#endif -+ -+ sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr); -+ sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr); -+ -+ chip->state = FL_ERASING; -+ -+ ret = sharp_do_wait_for_ready(map,chip,adr); -+ if(ret<0) { -+ spin_unlock_bh(chip->mutex); -+ return ret; -+ } -+ -+ sharp_send_cmd(map, CMD_READ_STATUS, adr); -+ status = map_read(map, adr); -+ -+ if (!(status.x[0] & SR_ERRORS)) { -+ sharp_send_cmd(map, CMD_RESET, adr); -+ chip->state = FL_READY; -+ spin_unlock_bh(chip->mutex); -+ return 0; -+ } -+ -+ printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]); -+ sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -+ -+ sharp_release(chip); -+ -+ return -EIO; -+} -+ -+#ifdef AUTOUNLOCK -+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, -+ unsigned long adr) -+{ -+ map_word status; -+ -+ sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr & BLOCK_MASK); -+ sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr & BLOCK_MASK); -+ -+ sharp_do_wait_for_ready(map,chip,adr); -+ -+ status = map_read(map, adr); -+ -+ if (!(status.x[0] & SR_ERRORS)) { -+ sharp_send_cmd(map, CMD_RESET, adr); -+ chip->state = FL_READY; -+ return; -+ } -+ -+ printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]); -+ sharp_send_cmd(map, CMD_CLEAR_STATUS, adr); -+} -+#endif -+ -+static void sharp_sync(struct mtd_info *mtd) -+{ -+} -+ -+static int sharp_suspend(struct mtd_info *mtd) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ int i; -+ struct flchip *chip; -+ int ret = 0; -+ -+ for (i = 0; !ret && i < sharp->numchips; i++) { -+ chip = &sharp->chips[i]; -+ ret = sharp_wait(map,chip); -+ -+ if (ret) { -+ ret = -EAGAIN; -+ } else { -+ chip->state = FL_PM_SUSPENDED; -+ spin_unlock_bh(chip->mutex); -+ } -+ } -+ return ret; -+} -+ -+static void sharp_resume(struct mtd_info *mtd) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ int i; -+ struct flchip *chip; -+ -+ for (i = 0; i < sharp->numchips; i++) { -+ chip = &sharp->chips[i]; -+ -+ spin_lock_bh(chip->mutex); -+ -+ if (chip->state == FL_PM_SUSPENDED) { -+ /* We need to force it back to a known state */ -+ sharp_send_cmd(map, CMD_RESET, chip->start); -+ chip->state = FL_READY; -+ wake_up(&chip->wq); -+ } -+ -+ spin_unlock_bh(chip->mutex); -+ } -+} -+ -+static void sharp_destroy(struct mtd_info *mtd) -+{ -+ struct map_info *map = mtd->priv; -+ struct sharp_info *sharp = map->fldrv_priv; -+ -+ kfree(sharp); -+} -+ -+static int __init sharp_probe_init(void) -+{ -+ printk("MTD Sharp chip driver <ds@lineo.com>\n"); -+ -+ register_mtd_chip_driver(&sharp_chipdrv); -+ -+ return 0; -+} -+ -+static void __exit sharp_probe_exit(void) -+{ -+ unregister_mtd_chip_driver(&sharp_chipdrv); -+} -+ -+module_init(sharp_probe_init); -+module_exit(sharp_probe_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Schleef <ds@schleef.org>"); -+MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips"); -Index: linux-2.6.26/drivers/mtd/maps/Kconfig -=================================================================== ---- linux-2.6.26.orig/drivers/mtd/maps/Kconfig 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/mtd/maps/Kconfig 2008-10-17 18:15:31.431789839 +0200 -@@ -392,7 +392,7 @@ - - config MTD_SA1100 - tristate "CFI Flash device mapped on StrongARM SA11x0" -- depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS -+ depends on (MTD_CFI || MTD_SHARP) && ARCH_SA1100 && MTD_PARTITIONS - help - This enables access to the flash chips on most platforms based on - the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. -Index: linux-2.6.26/drivers/mtd/maps/sa1100-flash.c -=================================================================== ---- linux-2.6.26.orig/drivers/mtd/maps/sa1100-flash.c 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/mtd/maps/sa1100-flash.c 2008-10-17 18:15:31.431789839 +0200 -@@ -210,6 +210,12 @@ - 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, -Index: linux-2.6.26/drivers/net/wireless/hostap/hostap_cs.c -=================================================================== ---- linux-2.6.26.orig/drivers/net/wireless/hostap/hostap_cs.c 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/net/wireless/hostap/hostap_cs.c 2008-10-17 18:15:31.435790279 +0200 -@@ -35,7 +35,7 @@ - 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 @@ - - 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; - } -Index: linux-2.6.26/drivers/net/wireless/hostap/hostap_hw.c -=================================================================== ---- linux-2.6.26.orig/drivers/net/wireless/hostap/hostap_hw.c 2008-10-17 18:13:21.000000000 +0200 -+++ linux-2.6.26/drivers/net/wireless/hostap/hostap_hw.c 2008-10-17 18:15:31.443789719 +0200 -@@ -54,6 +54,7 @@ - #include "hostap.h" - #include "hostap_ap.h" - -+extern int activar; - - /* #define final_version */ - -@@ -1534,6 +1535,8 @@ - if (local->hw_downloading) - return 1; - -+ activar=1; -+ - if (prism2_hw_init(dev, initial)) { - return local->no_pri ? 0 : 1; - } -@@ -2665,8 +2668,15 @@ - 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; - - if(dev->base_addr == 0) - { -Index: linux-2.6.26/drivers/net/wireless/hostap/hostap_pci.c -=================================================================== ---- linux-2.6.26.orig/drivers/net/wireless/hostap/hostap_pci.c 2008-10-17 18:13:18.000000000 +0200 -+++ linux-2.6.26/drivers/net/wireless/hostap/hostap_pci.c 2008-10-17 18:15:31.447790279 +0200 -@@ -19,6 +19,7 @@ - - #include "hostap_wlan.h" - -+int activar=1; - - static char *dev_info = "hostap_pci"; - -Index: linux-2.6.26/drivers/net/wireless/hostap/hostap_plx.c -=================================================================== ---- linux-2.6.26.orig/drivers/net/wireless/hostap/hostap_plx.c 2008-10-17 18:13:18.000000000 +0200 -+++ linux-2.6.26/drivers/net/wireless/hostap/hostap_plx.c 2008-10-17 18:15:31.451790719 +0200 -@@ -21,7 +21,7 @@ - #include <asm/io.h> - - #include "hostap_wlan.h" -- -+int activar=1; - - static char *dev_info = "hostap_plx"; - -Index: linux-2.6.26/drivers/pcmcia/sa1100_generic.c -=================================================================== ---- linux-2.6.26.orig/drivers/pcmcia/sa1100_generic.c 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/pcmcia/sa1100_generic.c 2008-10-17 18:15:31.459789719 +0200 -@@ -81,13 +81,14 @@ - 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 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 void __exit sa11x0_pcmcia_exit(void) - { -- driver_unregister(&sa11x0_pcmcia_driver); -+ platform_driver_unregister(&sa11x0_pcmcia_driver); - } - - MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); -Index: linux-2.6.26/drivers/spi/Kconfig -=================================================================== ---- linux-2.6.26.orig/drivers/spi/Kconfig 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/spi/Kconfig 2008-10-17 18:15:31.463790519 +0200 -@@ -123,6 +123,10 @@ - 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 -Index: linux-2.6.26/drivers/spi/Makefile -=================================================================== ---- linux-2.6.26.orig/drivers/spi/Makefile 2008-07-13 23:51:29.000000000 +0200 -+++ linux-2.6.26/drivers/spi/Makefile 2008-10-17 18:15:31.463790519 +0200 -@@ -28,6 +28,7 @@ - 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) -Index: linux-2.6.26/drivers/spi/locomo_spi.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.26/drivers/spi/locomo_spi.c 2008-10-17 18:15:31.471790439 +0200 -@@ -0,0 +1,1097 @@ -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/stat.h> -+#include <linux/delay.h> -+#include <linux/wait.h> -+#include <linux/interrupt.h> -+#include <asm/hardware/locomo.h> -+#include <asm/errno.h> -+#include <linux/mmc/host.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/mmc_spi.h> -+#include <linux/workqueue.h> -+#include <linux/spinlock.h> -+#include <linux/list.h> -+#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; i<size; i++){ -+ for(j=0; j <= wait; j++){ -+ if(ioread16(spidev->base+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; i<size; i++){ -+ for(j=0; j <= wait; j++){ -+ if(ioread16(spidev->base+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; i<size; i++){ -+ -+ for(j=0; j <= wait; j++){ -+ if(ioread16(spidev->base+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; i<LCM; i++){ -+ sprintf(c,"%s:\t\t 0x%x\n",locomo_regs[i].name, ioread16(base + locomo_regs[i].addr)); -+ strcat(b,c); -+ } -+ return sprintf(buf,"%s",b); -+} -+ -+static DRIVER_ATTR(regs, 0444, lcm_show, NULL); -+ -+ -+/* SPI functions *************************************************************/ -+ -+static void locomospi_do_transfer(struct work_struct *wrk) -+{ -+ struct list_head *mptr, *tptr, *mptr2; -+ struct spi_transfer *entry; -+ struct spi_message *msg; -+ -+ list_for_each_safe(mptr, mptr2, &spidev->message_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, "failed to register spimaster\n"); -+ goto wq; -+ } -+ return 0; -+wq: -+ destroy_workqueue(spidev->workqueue); -+irq4: -+// free_irq(IRQ_LOCOMO_SPI_TEND, (void*) spidev); -+irq3: -+// free_irq(IRQ_LOCOMO_SPI_REND, (void*) spidev); -+irq2: -+// free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev); -+irq1: -+// free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev); -+regdev: -+ spi_unregister_device(spidev->sdev); -+master: -+ spi_master_put(spidev->master); -+region: -+ release_mem_region((unsigned long) dev->mapbase, dev->length); -+ kfree(spidev); -+ return result; -+ -+} -+ -+static int locomospi_remove(struct locomo_dev *dev) -+{ -+ spi_unregister_device(spidev->sdev); -+ spi_unregister_master(spidev->master); -+ destroy_workqueue(spidev->workqueue); -+ locomospi_reg_release(); -+// free_irq(IRQ_LOCOMO_SPI_TEND, (void*) spidev); -+// free_irq(IRQ_LOCOMO_SPI_REND, (void*) spidev); -+// free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev); -+// free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev); -+ spi_master_put(spidev->master); -+ release_mem_region((unsigned long) dev->mapbase, dev->length); -+ kfree(spidev); -+ return 0; -+} -+ -+ -+ -+static int __init locomospi_init(void) -+{ -+ int ret = locomo_driver_register(&locomo_spi_driver); -+ if (ret) -+ return ret; -+ -+ -+ return 0; -+} -+ -+static void __exit locomospi_exit(void) -+{ -+ locomo_driver_unregister(&locomo_spi_driver); -+} -+ -+module_init(locomospi_init); -+module_exit(locomospi_exit); -+ -+MODULE_AUTHOR("Thomas Kunze thommy@tabao.de"); -+MODULE_DESCRIPTION("Collie mmc driver"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.26/drivers/spi/locomo_spi.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.26/drivers/spi/locomo_spi.h 2008-10-17 18:15:31.471790439 +0200 -@@ -0,0 +1,75 @@ -+#include <asm/hardware/locomo.h> -+#ifndef __LOCOMO_SPI_H__ -+#define __LOCOMO_SPI_H__ -+ -+/* locomo-spi status register LOCOMO_SPIST */ -+#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */ -+#define LOCOMO_SPI_REND (1 << 2) /* Receive end bit */ -+#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */ -+#define LOCOMO_SPI_RFR (1) /* read buffer bit */ -+ -+/* locomo-spi mode register LOCOMO_SPIMD */ -+#define LOCOMO_SPI_LOOPBACK (1 << 15) /* loopback tx to rx */ -+#define LOCOMO_SPI_MSB1ST (1 << 14) /* send MSB first */ -+#define LOCOMO_SPI_DOSTAT (1 << 13) /* transmit line is idle high */ -+#define LOCOMO_SPI_TCPOL (1 << 11) /* transmit CPOL (maybe affects CPHA too) */ -+#define LOCOMO_SPI_RCPOL (1 << 10) /* receive CPOL (maybe affects CPHA too) */ -+#define LOCOMO_SPI_TDINV (1 << 9) /* invert transmit line */ -+#define LOCOMO_SPI_RDINV (1 << 8) /* invert receive line */ -+#define LOCOMO_SPI_XON (1 << 7) /* enable spi controller clock */ -+#define LOCOMO_SPI_XEN (1 << 6) /* clock bit write enable xon must be off, wait 300 us before xon->1 */ -+#define LOCOMO_SPI_XSEL 0x0018 /* clock select */ -+#define CLOCK_18MHZ 0 /* 18,432 MHz clock */ -+#define CLOCK_22MHZ 1 /* 22,5792 MHz clock */ -+#define CLOCK_25MHZ 2 /* 24,576 MHz clock */ -+#define LOCOMO_SPI_CLKSEL 0x7 -+#define DIV_1 0 /* don't divide clock */ -+#define DIV_2 1 /* divide clock by two */ -+#define DIV_4 2 /* divide clock by four */ -+#define DIV_8 3 /* divide clock by eight*/ -+#define DIV_64 4 /* divide clock by 64 */ -+ -+/* locomo-spi control register LOCOMO_SPICT */ -+#define LOCOMO_SPI_CRC16_7_B (1 << 15) /* 0: crc16 1: crc7 */ -+#define LOCOMO_SPI_CRCRX_TX_B (1 << 14) -+#define LOCOMO_SPI_CRCRESET_B (1 << 13) -+#define LOCOMO_SPI_CEN (1 << 7) /* ?? enable */ -+#define LOCOMO_SPI_CS (1 << 6) /* chip select */ -+#define LOCOMO_SPI_UNIT16 (1 << 5) /* 0: 8 bit units, 1: 16 bit unit */ -+#define LOCOMO_SPI_ALIGNEN (1 << 2) /* align transfer enable */ -+#define LOCOMO_SPI_RXWEN (1 << 1) /* continous receive */ -+#define LOCOMO_SPI_RXUEN (1 << 0) /* aligned receive */ -+ -+#define IRQ_LOCOMO_CARDDETECT IRQ_LOCOMO_GPIO13 -+ -+ -+struct locomospi_dev { -+ struct locomo_dev *ldev; -+ struct spi_master *master; -+ struct spi_device *sdev; -+ int card_power; -+ int clock_base; -+ int clock_div; -+ int clock; -+ unsigned long base; -+ u8 spimode; -+ wait_queue_head_t waitqueue; -+ struct workqueue_struct *workqueue; -+ struct list_head message_list; -+ spinlock_t message_lock; -+}; -+ -+ -+static irqreturn_t locomospi_cardisr(int, void*); -+static int locomospi_probe(struct locomo_dev*); -+static int locomospi_remove(struct locomo_dev*); -+static int locomospi_carddetect(void); -+static void locomospi_reg_open(void); -+static void locomospi_reg_release(void); -+static int tx(const char*, int); -+static int rx(char *, int); -+static void locomospi_power(int on); -+static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state); -+static int locomospi_resume(struct locomo_dev *dev); -+static void locomospi_setcs(int high); -+#endif |