diff options
Diffstat (limited to 'packages/linux/linux-ezx/pxa-spi.patch')
-rw-r--r-- | packages/linux/linux-ezx/pxa-spi.patch | 1041 |
1 files changed, 0 insertions, 1041 deletions
diff --git a/packages/linux/linux-ezx/pxa-spi.patch b/packages/linux/linux-ezx/pxa-spi.patch deleted file mode 100644 index c0f66a8246..0000000000 --- a/packages/linux/linux-ezx/pxa-spi.patch +++ /dev/null @@ -1,1041 +0,0 @@ -Index: linux-2.6.16.5-ezx/arch/arm/mach-pxa/ezx-pcap.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16.5-ezx/arch/arm/mach-pxa/ezx-pcap.c 2006-05-04 00:38:11.000000000 +0200 -@@ -0,0 +1,344 @@ -+/* Driver for Motorola PCAP2 as present in EZX phones -+ * -+ * This is both a SPI device driver for PCAP itself, as well as -+ * an IRQ demultiplexer for handling PCAP generated events such as -+ * headphone jack sense by downstream drivers. -+ * -+ * (C) 2006 by Harald Welte <laforge@openezx.org> -+ */ -+ -+#include <linux/config.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/spi/spi.h> -+ -+#include <asm/arch/ezx-pcap.h> -+ -+/* lowlevel functions for register access */ -+ -+static struct { -+ struct spi_transfer transfer; -+ u_int32_t rx_buf; -+ u_int32_t tx_buf; -+ spinlock_t lock; /* lock protecting transfer + buffers */ -+} pcap_spi; -+ -+ -+int ezx_pcap_write(u_int8_t reg_num, u_int32_t value) -+{ -+ int ret; -+ u_int32_t frame; -+ value &= SSP_PCAP_REGISTER_VALUE_MASK; -+ -+ spin_lock(&pcap_spi.lock); -+ -+ pcap_spi.tx_buf = value | SSP_PCAP_REGISTER_WRITE_OP_BIT -+ |(reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); -+ -+ /* we need to disable IRQ_GPIO1 because it's hardirq handler will -+ * in turn want to use SPI to get the real interrupt source */ -+ irq_disable(IRQ_GPIO1); -+ ret = spi_sync_nosleep_x(pcap_spi_dev, &pcap_spi.transfer); -+ irq_enable(IRQ_GPIO1); -+ -+ spin_unlock(&pcap_spi.lock); -+ -+ return ret; -+ -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_write); -+ -+int ezx_pcap_read(u_int8_t reg_num, u_int32_t *value) -+{ -+ int ret; -+ u_int32_t frame; -+ value &= SSP_PCAP_REGISTER_VALUE_MASK; -+ -+ spin_lock(&pcap_spi.lock); -+ -+ -+ pcap_spi.tx_buf = SSP_PCAP_REGISTER_READ_OP_BIT -+ | (reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); -+ -+ /* we need to disable IRQ_GPIO1 because it's hardirq handler will -+ * in turn want to use SPI to get the real interrupt source */ -+ irq_disable(IRQ_GPIO1); -+ ret = spi_sync_nosleep_x(pcap_spi_dev, &pcap_spi.transfer); -+ irq_enable(IRQ_GPIO1) -+ -+ if (ret >= 0) -+ *value = pcap_spi.transfer.rx_buf; -+ -+ spin_unlock(&pcap_spi.lock); -+ -+ return ret; -+ -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_read); -+ -+int ezx_pcap_bit_set(u_int32_t sspPcapBit, u_int8_t to) -+{ -+ u_int32_t sspPcapRegisterBitValue; -+ int ret; -+ u_int8_t reg_num = (sspPcapBit & SSP_PCAP_REGISTER_ADDRESS_MASK) -+ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; -+ -+ if (reg_num == SSP_PCAP_ADJ_ISR_REGISTER) -+ ssp_pcap_registerValue[reg_num] = 0; -+ -+ sspPcapRegisterBitValue = (sspPcapBit & SSP_PCAP_REGISTER_VALUE_MASK); -+ -+ if (to == 0) -+ ssp_pcap_registerValue[sspPcapRegister] |= sspPcapRegisterBitValue; -+ else -+ ssp_pcap_registerValue[sspPcapRegister] &= ~sspPcapRegisterBitValue; -+ -+ /* should care the return value */ -+ return ezx_pcap_write(num_reg, ssp_pcap_registerValue[num_reg]); -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_bit_set); -+ -+int ezx_pcap_read_bit(u_int32_t bit) -+{ -+ int ret; -+ u_int32_t tmp; -+ u_int8_t reg_num = (bit & SSP_PCAP_REGISTER_ADDRESS_MASK) -+ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; -+ -+ ret = ezx_pcap_read(reg_num, &tmp); -+ if (ret < 0) -+ return ret; -+ -+ return tmp & (bit & SSP_PCAP_REGISTER_VALUE_MASK); -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_read_bit); -+ -+static int ezx_pcap_init(void) -+{ -+ /* initialize our transfer structure */ -+ memset(&pcap_spi, 0, sizeof(pcap_spi)); -+ pcap_spi.transfer.tx_buf = &pcap_spi.tx_buf; -+ pcap_spi.transfer.rx_buf = &pcap_spi.rx_buf; -+ pcap_spi.transfer.len = 4; -+ -+ /* FIXME: resolve the spi_master and configure it apropriately */ -+ -+ /* initialize registers */ -+ /* FIXME: this should be board-level, not chip-level */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL, 1); -+#ifdef FIXME -+ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); -+ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); -+#endif -+ -+ /* set SW1 sleep to keep SW1 1.3v in sync mode */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11, 0); -+ /* SW1 active in sync mode */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01, 0); -+ /* at SW1 -core voltage to 1.30V */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS, 0); -+ -+ /* when STANDY2 PIN ACTIVE (high) set V3-- sram V8 -- pll off */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_STBY, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR, 0); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_STBY, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR, 0); -+ -+ /* when STANDY2 PIN ACTIVE (high) set V4-- lcd only for e680 V6 --- -+ * camera for e680 */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_STBY, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR, 1); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_STBY, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR, 0); -+ -+ /* set Vc to low power mode when AP sleep */ -+ //SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY); -+ -+ /* set VAUX2 to voltage 2.775V and low power mode when AP sleep */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); -+ -+#ifdef FIXME -+ PGSR(GPIO34_TXENB) |= GPIO_bit(GPIO34_TXENB); -+ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V )) -+ { -+ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); -+ } -+ else -+ { -+ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); -+ } -+#endif -+ return 0; -+} -+ -+int ezx_pcap_vibrator_level() -+{ -+ /* FIXME */ -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_vibrator_level); -+ -+ -+/* MMC/SD specific functions */ -+ -+int ezx_pcap_mmcsd_power(int on) -+{ -+ if (on) -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); -+ else -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 0); -+} -+EXPORT_SYMBOL_GPL(ezx_pcap_mmcsd_power); -+ -+/* IRQ Handling */ -+ -+/* Array indexed by BIT POSITION of PCAP register, returns IRQ number */ -+static unsigned int pcap2irq[] = { -+ 0 = EZX_IRQ_ADCDONE, -+ 1 = EZX_IRQ_TS, -+ [7] = EZX_IRQ_USB4V, -+ [10] = EZX_IRQ_USB1V, -+ [12] = EZX_IRQ_MIC, -+ [13] = EZX_IRQ_HEADJACK, -+}; -+ -+/* Array indexed by IRQ NUMBER, returns PCAP absolute value */ -+static unsigned int irq2pcap[] = { -+ [EZX_IRQ_ADCDONE] = SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I, -+ [EZX_IRQ_TS] = SSP_PCAP_ADJ_BIT_ISR_TSI, -+ [EZX_IRQ_USB4V] = SSP_PCAP_ADJ_BIT_ISR_USB4VI, -+ [EZX_IRQ_USB1V] = SSP_PCAP_ADJ_BIT_ISR_USB1VI, -+ [EZX_IRQ_HEADJACK] = SSP_PCAP_ADJ_BIT_ISR_A1I, -+ [EZX_IRQ_MIC] = SSP_PCAP_ADJ_BIT_ISR_MB2I, -+}; -+ -+static void pcap_ack_irq(unsigned int irq) -+{ -+ ezx_pcap_write(SSP_PCAP_ADJ_ISR_REGISTER, irq2pcap[irq]); -+} -+ -+static void pcap_mask_irq(unsigned int irq) -+{ -+ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, irq2pcap[irq]); -+} -+ -+static void pcap_unmask_irq(unsigned int irq) -+{ -+ u_int32_t tmp; -+ -+ /* this needs to be atomic... but we're not on SMP so it is */ -+ ezx_pcap_read(SSP_PCAP_ADJ_MSR_REGISTER, &tmp); -+ tmp &= ~irq2pcap[irq]; -+ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, tmp); -+} -+ -+static struct irqchip pcap_chip = { -+ .ack = pcap_ack_irq, -+ .mask = pcap_mask_irq, -+ .unmask = pcap_unmask_irq, -+}; -+ -+/* handler for interrupt received from PCAP via GPIO */ -+static void pcap_irq_demux_handler(unsigned int irq, struct irqdesc *desc, -+ struct pt_regs *regs) -+{ -+ int i; -+ u_int32_t reg; -+ -+ ezx_pcap_read(SSP_PCAP_ADJ_ISR_REGISTER, ®); -+ -+ for (i = 0; i < ARRAY_SIZE(pcap2irq); i++) { -+ unsigned int irq = pcap2irq[i]; -+ if (irq == 0) -+ continue; -+ if (reg & (1 << i)) -+ desc_handle_irq(irq, desc, regs); -+ } -+} -+ -+ -+/* SPI protocol driver initialization */ -+ -+static int __devinit ezx_pcap_probe(struct spi_device *spi) -+{ -+ unsigned int ret, irq; -+ struct ezx_pcap *chip; -+ -+ chip = kzalloc(sizeof(*chip), GFP_KERNEL); -+ if (!chip) -+ return ENOMEM; -+ -+ dev_set_drvdata(&spi->dev, chip); -+ -+ ret = ezx_pcap_init(); -+ if (ret < 0) -+ return ret; -+ -+ /* set up interrupt demultiplexing code for PCAP2 irqs */ -+ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(5); irq++) { -+ set_irq_chip(irq, &pcap_chip); -+ set_irq_handler(irq, do_edge_IRQ); -+ set_irq_flags(irq, IRQF_VALID); -+ } -+ -+ set_irq_chained_handler(IRQ_GPIO1, pcap_irq_demux_handler); -+ -+ return 0; -+} -+ -+static void __devexit ezx_pcap_remove(struct spi_device *spi) -+{ -+ /* remove interrupt demultiplexing code for PCAP2 irqs */ -+ set_irq_chained_handler(IRQ_GPIO1, NULL); -+ -+ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(5); irq++) { -+ set_irq_chip(irq, NULL); -+ set_irq_handler(irq, NULL); -+ set_irq_flags(irq, 0); -+ } -+ // kfree -+} -+ -+static struct spi_driver ezx_pcap_driver = { -+ .driver = { -+ .name = "ezx-pcap", -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ -+ .probe = ezx_pcap_probe, -+ .remove = __devexit_p(ezx_pcap_remove), -+} -+ -+ -+static int __init pcap_init(void) -+{ -+ return spi_register_driver(&ezx_pcap_driver); -+} -+ -+static void __exit pcap_fini(void) -+{ -+ spi_unregister_driver(&ezx_pcap_driver); -+} -+ -+module_init(pcap_init); -+module_exit(pcap_fini); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); -+MODULE_DESCRIPTION("SPI Driver for Motorola PCAP2"); -+ -Index: linux-2.6.16.5-ezx/arch/arm/mach-pxa/ezx.c -=================================================================== ---- linux-2.6.16.5-ezx.orig/arch/arm/mach-pxa/ezx.c 2006-05-03 14:41:58.000000000 +0200 -+++ linux-2.6.16.5-ezx/arch/arm/mach-pxa/ezx.c 2006-05-03 14:49:25.000000000 +0200 -@@ -492,17 +492,61 @@ - - /* touch screen */ - -+/* SPI master devices */ - --/* SSP device */ -+static int ezx_spi_init(unsigned int num) -+{ -+ switch (num) { -+ case 1: -+ pxa_gpio_mode(GPIO24_SFRM_MD); -+ pxa_gpio_mode(GPIO25_STXD_MD); -+ pxa_gpio_mode(GPIO26_SRXD_MD); -+ pxa_gpio_mode(GPIO29_SCLK_MD); -+ break; -+ case 2: -+ pxa_gpio_mode(GPIO22_SCLK2_MD); -+ pxa_gpio_mode(GPIO37_SFRM2_MD); -+ pxa_gpio_mode(GPIO38_STXD2_MD); -+ pxa_gpio_mode(GPIO88_SRXD2_MD); -+ break; -+ case 3: -+ pxa_gpio_mode(GPIO52_SCLK3_MD); -+ pxa_gpio_mode(GPIO83_SFRM3_MD); -+ pxa_gpio_mode(GPIO81_STXD3_MD); -+ pxa_gpio_mode(GPIO89_SRXD3_MD); -+ break; -+ default: -+ return -ENODEV; -+ } - --static struct platform_device ezx_ssp_pcap_device = { -- .name = "ezx-ssp-pcap", -- .dev = { -- //.parent = , -- }, -- .id = -1, -+ return 0; -+} -+ -+static struct pxa_spi_data { -+ .init = &ezx_spi_init, - }; - -+/* SPI/SSP controller devices */ -+ -+static struct spi_board_info spi_board_info[] __initdata = { -+ { -+ .modalias = "ezx-pcap", -+ .mode = SPI_MODE_0, -+ .max_speed_hz = /* FIXME */, -+ .bus_num = 1, -+ .irq = IRQ_GPIO1, -+ }, { -+ .modalias = "ezx-snd", -+ .mode = SPI_MODE_0, -+ .max_speed_hz = /* FIXME */, -+ .bus_num = 2, -+ }, { -+ .modalias = "ezx-snd", -+ .mode = SPI_MODE_0, -+ .max_speed_hz = /* FIXME */, -+ .bus_num = 3, -+ }, -+} - - static int step = FIRST_STEP; - void handshake(void) -@@ -704,7 +748,7 @@ - - static struct platform_device *devices[] __initdata = { - &ezx_bp_device, -- &ezx_ssp_pcap_device, -+ //&ezx_ssp_pcap_device, - }; - - static void __init -@@ -806,6 +850,14 @@ - #endif - - platform_add_devices(devices, ARRAY_SIZE(devices)); -+ -+ /* register all three SPI busses */ -+ pxa_register_spi(1, &pxa_spi_data); -+ //pxa_register_spi(2, &pxa_spi_data); -+ //pxa_register_spi(3, &pxa_spi_data); -+ -+ /* register information about SPI slaves attached to SPI */ -+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); - } - - MACHINE_START(EZX, "Motorola Ezx Platform") -Index: linux-2.6.16.5-ezx/arch/arm/mach-pxa/spi.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.16.5-ezx/arch/arm/mach-pxa/spi.c 2006-05-04 00:40:25.000000000 +0200 -@@ -0,0 +1,486 @@ -+#include <linux/config.h> -+#include <linux/errno.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/workqueue.h> -+#include <linux/platform_device.h> -+ -+#include <linux/spi/spi.h> -+ -+#include <asm/arch/pxa-regs.h> -+ -+/* board-specific data for one SPI controller */ -+struct pxa_spi_data { -+ int (init)(unsigned int n); -+}; -+ -+/* */ -+struct pxa_master { -+ struct workqueue_struct *workqueue; -+ struct work_struct work; -+ -+ atomic_t busy; -+ spinlock_t lock; -+ struct list_head queue; -+ -+ struct spi_master *master; -+ -+ int port; -+}; -+ -+static void ssp_enable(unsigned int port) -+{ -+ SSCR0_P(port) &= ~SSCR0_SSE; -+} -+ -+static void ssp_disable(unsigned int port) -+{ -+ SSCR0_P(port) |= SSCR0_SSE; -+} -+ -+/* low level utility functions, mainly copied from arch/arm/mach-pxa/ssp.c */ -+static int ssp_config(unsigned int port, u_int32_t mode, u_int32_t flags, -+ u_int32_t psp_flags, u_int32_t speed) -+{ -+ SSCR0_P(port) = (dev->speed | dev->mode); -+ SSCR1_P(port) = dev->flags; -+ SSPSP_P(port) = dev->psp_flags; -+ -+ return 0; -+} -+ -+static int ssp_write_word(struct ssp_dev *dev, u32 data) -+{ -+ while (!(SSSR_P(dev->port) & SSSR_TNF)) -+ cpu_relax(); -+ -+ SSDR_P(dev->port) = data; -+ -+ return 0; -+} -+ -+static u_int32_t ssp_read_word(struct ssp_dev *dev) -+{ -+ while (!(SSSR_P(dev->port) & SSSR_RNE)) -+ cpu_relax(); -+ -+ return SSDR_P(dev->port); -+} -+ -+static irqreturn_t pxa_spi_interrupt(int irq, void *dev_id, -+ struct pt_regs *regs) -+{ -+ struct spi_master *master = (struct spi_master *) dev_id; -+ struct pxa_master *pm = master->private; -+ unsigned int status = SSSR_P(pm->port); -+ -+ SSSR_P(dev->port) = status; /* clear status bits */ -+ -+ if (status & SSSR_ROR) -+ pritnk(KERN_WARNING "SPI(%d): receiver overrun\n", pm->port); -+ if (status & SSSR_TUR) -+ printk(KERN_WARNING "SPI(%d): transmitter underrun\n", -+ pm->port); -+ -+ if (status & SSSR_BCE) -+ printk(KERN_WARNING "SPI(%d): bit count error\n", pm->port); -+ -+ return IRQ_HANDLED; -+} -+ -+static int pxa_spi_setup(struct spi_device *spi) -+{ -+ struct pxa_master *pm; -+ u_int32_t mode, flags, div; -+ -+ if (!spi->max_speed_hz) -+ return -EINVAL; -+ -+ if (spi->bits_per_word < 4 || -+ spi->bits_per_word > 32) -+ return -EINVAL; -+ -+ if (!spi->bits_per_word) -+ spi->bits_per_word = 8; -+ -+ pm = spi_master_get_devdata(spi->master); -+ -+ mode = SSCR0_Motorola; /* SPI, FIXME: other modes such as SSP! */ -+ flags = 0; -+ -+ /* clock phase and polarity */ -+ if (spi->mode & SPI_CPHA) -+ flags |= SSCR1_SPH; -+ if (spi->mode & SPI_CPOL) -+ flags |= SSCR1_SPO; -+ -+ /* word size */ -+ mode |= (spi->bits_per_word & 0xf); -+ if (spi->bits_per_word > 16) -+ mode |= SSCR0_EDSS; -+ -+#define PXA27x_SPI_CLOCK (13*1000*1000) -+ div = PXA27x_SPI_CLOCK / spi->max_speed_hz; -+ -+ return ssp_config(pm->port, mode, flags, 0, SSCR0_SerClkDiv(div)); -+} -+ -+/* just add an SPI transfer to the workqueue */ -+static int pxa_spi_transfer(struct spi_device *spi, struct spi_message *msg) -+{ -+ struct pxa_master *pm; -+ unsigned long flags; -+ -+ pm = spi_master_get_devdata(spi->master); -+ -+ spin_lock_irqsave(&pm->lock, flags); -+ -+ list_add_tail(&m->queue, &pm->queue); -+ queue_work(pm->workqueue, &pm->work); -+ -+ spin_unlock_irqrestore(&pm->lock, flags); -+} -+ -+/* the actualy workqueue dequeueing workhorse */ -+static void pxa_spi_work(void *_pxa_master) -+{ -+ struct pxa_master *pm = _pxa_master; -+ unsigned long flags; -+ -+ spn_lock_irqsave(&pm->lock, flags); -+ atomic_inc(&pm->busy); -+ -+ while (!list_empty(&pm->queue)) { -+ struct spi_message *m; -+ struct spi_device *spi; -+ struct spi_transfer *t = NULL; -+ int status; -+ -+ m = container_of(pm->queue.next, struct spi_message, queue); -+ list_del_init(&m->queue); -+ spin_unlock_irqrestore(&pm->lock, flags); -+ -+ spi = m->spi; -+ cs_change = 1; -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ -+#ifdef LATER -+ if (cs_change) { -+ pm->chipselect(spi, BITBANG_CS_ACTIVE); -+ } -+ cs_change = t->cs_change; -+#endif -+ -+ if (!t->tx_buf && !t->rx_buf && t->len) { -+ status = -EINVAL; -+ break; -+ } -+ -+ if (t->len) { -+ if (!m->is_dma_mapped) -+ t->rx_dma = t->tx_dma = 0; -+ status = pxa_spi_transfer_x(t); -+ } -+ if (status != t->len) { -+ if (status > 0) -+ status = -EMSGSIZE; -+ break; -+ } -+ m->actual_length += status; -+ status = 0; -+ -+ if (t->delay_usecs) -+ udelay(t->delay_usecs); -+ -+ if (!cs_change) -+ continue; -+ if (t->transfer_list.next == &m->transfers) -+ break; -+ -+#ifdef LATER -+ pm->chipselect(spi, BITBANG_CS_INACTIVE); -+#endif -+ } -+ -+ m->status = status; -+ m->complete(m->context); -+ -+#ifdef LATER -+ if (!(status == 0 && cs_change)) -+ pm->chipselect(spi, BITBANG_CS_INACTIVE); -+#endif -+ -+ spin_lock_irqsave(&pm->lock, flags); -+ } -+ atomic_dec(&pm->busy); -+ spin_unlock_irqrestore(&pm->lock, flags); -+} -+ -+/* actually transfer a given message */ -+static int pxa_spi_transfer_x(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct spi_master *master = spi->master; -+ struct pxa_master *pm = spi_master_get_devdata(master); -+ unsigned int i, n; -+ -+ ssp_enable(pm->port); -+ -+ /* calculate number of bytes per fifo-write/read */ -+ n = spi->bits_per_word / 8; -+ if (spi->bits_per_word % 8) -+ n++; -+ -+ /* FIXME: What about endianness? */ -+ for (i = 0; i < t->len; i += n) { -+ u_int32_t tx, rx; -+ if (n == 1) { -+ tx = t->tx_buf[i]; -+ ssp_write_word(pm->port, tx); -+ rx = ssp_read_word(pm->port); -+ t->rx_buf[i] = rx & 0xff -+ t->rx_buf[i+1] = rx >> 8; -+ } else if (n == 3) { -+ tx = t->tx_buf[i] | t->tx_buf[i+1] << 8 | t->tx_buf[i+2] << 16; -+ ssp_write_word(pm->port, tx); -+ rx = ssp_read_word(pm->port); -+ t->rx_buf[i] = rx & 0xff; -+ t->rx_buf[i+1] = rx >> 8; -+ t->rx_buf[i+2] = rx >> 16; -+ } else { -+ tx = t->tx_buf[i] | t->tx_buf[i+1] << 8; -+ tx |= t->tx_buf[i+2] << 16 | t->tx_buf[i+3] << 24; -+ ssp_write_word(pm->port, tx); -+ rx = ssp_read_word(pm->port); -+ t->rx_buf[i] = rx & 0xff; -+ t->rx_buf[i+1] = rx >> 8; -+ t->rx_buf[i+2] = rx >> 16; -+ t->rx_buf[i+3] = rx >> 24; -+ } -+ } -+ ssp_disable(pm->port); -+ -+ return 0; -+} -+ -+static int pxa_spi_cleanup(struct spi_device *spi) -+{ -+ //FIXME; -+ return 0; -+} -+ -+/* non-standard really-synchronous non-sleeping SPI handling */ -+int spi_sync_xfer_nosleep(struct spi_device *spi, struct spi_transfer *x) -+{ -+ return pxa_spi_trasnfer_x(spi, x); -+} -+EXPORT_SYMBOL_GPL(spi_sync_xfer_nosleep); -+ -+void pxa_spi_probe(struct platform_device *pdev) -+{ -+ struct resource *mem_res; -+ struct pxa_master *pm; -+ struct spi_master *master; -+ int ret = -ENOMEM; -+ -+ pm = kzalloc(sizeof(*pm), GFP_KERNEL); -+ if (!pm) -+ return err; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*pp)); -+ if (!master) -+ goto out_pm; -+ -+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!mem_res) { -+ ret = -EINVAL; -+ goto out_mem; -+ } -+ -+ /* request register memory region */ -+ if (!request_mem_region(mem_res->start, mem_res->end - mem_res->start, -+ "pxa-spi")) { -+ ret = -EBUSY; -+ goto out_master; -+ } -+ -+ if (!request_irq(platform_get_irq(pdev, 0), pxa_spi_interrupt, -+ 0, "pxa-spi", master)) { -+ ret = -EBUSY; -+ goto out_mem; -+ } -+ -+ pm->master = master; -+ /* FIXME: this is still PXA27x specific */ -+ switch (mem_res->start) { -+ case SSCR0_1: -+ pm->port = 1; -+ break; -+ case SSCR0_2: -+ pm->port = 2; -+ break; -+ case SSCR0_3: -+ pm->port = 3; -+ break; -+ default: -+ ret = -EINVAL; -+ goto out_irq; -+ } -+ INIT_WORK(&pm->work, pxa_spi_work, pm); -+ spin_lock_init(&pm->lock); -+ INIT_LIST_HEAD(&pm->queue); -+ -+ pm->workqueue = create_singlethread_workqueue( -+ master->cdev.dev->bus_id); -+ if (!pm->workqueue) { -+ ret = -EBUSY; -+ goto out_irq; -+ } -+ -+ master->cleanup = &pxa_spi_cleanup; -+ master->setup = &pxa_spi_setup; -+ master->transfer = &pxa_spi_transfer; -+ master->transfer_nosleep = &spi_sync_xfer_nosleep; -+ master->private = pm; -+ -+ /* FIXME: this is still PXA27x specific */ -+ if (pm->port == 1) -+ pxa_set_cken(CKEN23_SSP1); -+ else if (pm->port == 2) -+ pxa_set_cken(CKEN3_SSP2); -+ else -+ pxa_set_cken(CKEN4_SSP3); -+ -+ ret = spi_register_master(master); -+ if (ret < 0) -+ goto out_workqueue; -+ -+ platform_set_drvdata(pdev, pm); -+ -+ return 0; -+ -+out_workqueue: -+ destroy_workqueue(pm->workqueue); -+out_irq: -+ free_irq(platform_get_irq(pdev, 0)); -+out_mem: -+ release_mem_region(mem_res->start, mem_res->end-mem_res->start); -+out_master: -+ spi_free_master(master); -+out_pm: -+ kfree(pm); -+ -+ return ret; -+} -+ -+void pxa_spi_remove() -+{ -+} -+ -+static struct platform_driver pxa_spi_driver = { -+ .probe = pxa_spi_probe, -+ .remove = pxa_spi_remove, -+ .driver = { -+ .name = "pxa-spi", -+ }, -+}; -+ -+static int __init pxa_spi_init(void) -+{ -+ return platform_driver_register(&pxa_spi_driver); -+} -+ -+static void __exit pxa_spi_fini(void) -+{ -+ platform_driver_unregister(&pxa_spi_driver); -+} -+ -+module_init(pxa_spi_init); -+module_exit(pxa_spi_fini); -+ -+/* SPI/SSP master (controller) platform devices, registered by board-level init -+ * code calling pxa_register_spi() */ -+ -+/* FIXME: this is still PXA27x specific */ -+static struct resource pxa_spi1_resources[] = { -+ { -+ .start = SSCR0_1, -+ .end = SSACD_1, -+ .flags = IORESOURCE_MEM, -+ }, { -+ .start = IRQ_SSP, -+ .end = IRQ_SSP, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+static struct resource pxa_spi2_resources[] = { -+ { -+ .start = SSCR0_2, -+ .end = SSACD_2, -+ .flags = IORESOURCE_MEM, -+ }, { -+ .start = IRQ_SSP2, -+ .end = IRQ_SSP2, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+static struct resource pxa_spi3_resources[] = { -+ { -+ .start = SSCR0_3, -+ .end = SSACD_3, -+ .flags = IORESOURCE_MEM, -+ }, { -+ .start = IRQ_SSP3, -+ .end = IRQ_SSP3, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static struct platform_device pxa_spi_devices[] = { -+ { -+ .name = "pxa-spi", -+ .dev = { -+ }, -+ .id = -1, -+ .resources = pxa_spi1_resources, -+ .num_resourcs = ARRAY_SIZE(pxa_spi1_resources), -+ },{ -+ .name = "pxa-spi", -+ .dev = { -+ }, -+ .id = -1, -+ .resources = pxa_spi2_resources, -+ .num_resources = ARRAY_SIZE(pxa_spi2_resources), -+ },{ -+ .name = "pxa-spi", -+ .dev = { -+ }, -+ .id = -1; -+ .resources = pxa_spi3_resources, -+ .num_resources = ARRAY_SIZE(pxa_spi3_resources), -+ }, -+}; -+ -+void pxa_register_spi(unsigned int n, struct pxa_spi_data *pdata) -+{ -+ if (n < 1 || n > 3) { -+ printk(KERN_WARN, "Board init code tries to use non-" -+ "existing SPI Bus %u\n", n); -+ return; -+ } -+ -+ /* n = 1..3, we need 0..2 */ -+ n--; -+ -+ pxa_spi_devices[n]->dev.platform_data = pdata; -+ register_platform_device(&pxa_spi_devices[n]); -+ -+ /* Setup GPIO alternate functions */ -+ if (pdata->init) -+ pdata->init(n); -+} -+EXPORT_SYMBOL_GPL(pxa_register_spi); -+ -+MODULE_DESCRIPTION("New PXA SPI/SSP driver"); -+MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.16.5-ezx/include/asm-arm/arch-pxa/irqs.h -=================================================================== ---- linux-2.6.16.5-ezx.orig/include/asm-arm/arch-pxa/irqs.h 2006-05-03 14:41:58.000000000 +0200 -+++ linux-2.6.16.5-ezx/include/asm-arm/arch-pxa/irqs.h 2006-05-03 14:42:00.000000000 +0200 -@@ -217,3 +217,12 @@ - #define IRQ_LOCOMO_GPIO_BASE (IRQ_BOARD_START + 1) - #define IRQ_LOCOMO_LT_BASE (IRQ_BOARD_START + 2) - #define IRQ_LOCOMO_SPI_BASE (IRQ_BOARD_START + 3) -+ -+/* EZX Interrupts (CONFIG_EZX) */ -+#define EZX_IRQ(x) (IRQ_BOARD_START + (x)) -+#define EZX_IRQ_ADCDONE EZX_IRQ(0) /* PCAP */ -+#define EZX_IRQ_TSM EZX_IRQ(1) /* PCAP */ -+#define EZX_IRQ_USB4V EZX_IRQ(2) /* PCAP */ -+#define EZZ_IRQ_USB1V EZX_IRQ(3) /* PCAP */ -+#define EZX_IRQ_HEADJACK EZX_IRQ(4) /* PCAP */ -+#define EZX_IRQ_MIC EZX_IRQ(5) /* PCAP */ -Index: linux-2.6.16.5-ezx/include/asm/arch/pxa-regs.h -=================================================================== ---- linux-2.6.16.5-ezx.orig/include/asm/arch/pxa-regs.h 2006-05-03 14:41:58.000000000 +0200 -+++ linux-2.6.16.5-ezx/include/asm/arch/pxa-regs.h 2006-05-03 14:42:01.000000000 +0200 -@@ -1374,6 +1374,7 @@ - #define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN) - #define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN) - #define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN) -+#define GPIO22_SCLK2_MD (22 | GPIO_ALT_FN_3_IN) - #define GPIO23_SCLK_MD (23 | GPIO_ALT_FN_2_OUT) - #define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT) - #define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) -@@ -1384,6 +1385,7 @@ - #define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT) - #define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) - #define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) -+#define GPIO29_SCLK_MD (29 | GPIO_ALT_FN_3_IN) - #define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) - #define GPIO30_USB_P3_2 (30 | GPIO_ALT_FN_3_OUT) - #define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) -@@ -1402,7 +1404,9 @@ - #define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) - #define GPIO36_USB_P2_4_MD (36 | GPIO_ALT_FN_1_OUT) - #define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) -+#define GPIO37_SFRM2_MD (37 | GPIO_ALT_FN_2_IN) - #define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) -+#define GPIO38_STXD2_MD (38 | GPIO_ALT_FN_2_OUT) - #define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) - #define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) - #define GPIO39_USB_P2_6_MD (39 | GPIO_ALT_FN_1_OUT) -@@ -1432,6 +1436,7 @@ - #define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT) - #define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) - #define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) -+#define GPIO52_SCLK3_MD (52 | GPIO_ALT_FN_2_OUT) - #define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) - #define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) - #define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) -@@ -1477,13 +1482,17 @@ - #define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT) - #define GPIO81_NSSP_CLK_OUT (81 | GPIO_ALT_FN_1_OUT) - #define GPIO81_NSSP_CLK_IN (81 | GPIO_ALT_FN_1_IN) -+#define GPIO81_STXD3_MD (81 | GPIO_ALT_FN_1_OUT) - #define GPIO82_NSSP_FRM_OUT (82 | GPIO_ALT_FN_1_OUT) - #define GPIO82_NSSP_FRM_IN (82 | GPIO_ALT_FN_1_IN) - #define GPIO83_NSSP_TX (83 | GPIO_ALT_FN_1_OUT) - #define GPIO83_NSSP_RX (83 | GPIO_ALT_FN_2_IN) -+#define GPIO83_SFRM3_MD (83 | GPIO_ALT_FN_1_IN) - #define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT) - #define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN) - #define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT) -+#define GPIO88_SRXD2_MD (88 | GPIO_ALT_FN_2_IN) -+#define GPIO90_SRXD3_MD (89 | GPIO_ALT_FN_1_IN) - #define GPIO90_USB_P3_5 (90 | GPIO_ALT_FN_2_IN) - #define GPIO91_USB_P3_1 (91 | GPIO_ALT_FN_2_IN) - #define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT) -Index: linux-2.6.16.5-ezx/include/linux/spi/spi.h -=================================================================== ---- linux-2.6.16.5-ezx.orig/include/linux/spi/spi.h 2006-05-03 15:11:08.000000000 +0200 -+++ linux-2.6.16.5-ezx/include/linux/spi/spi.h 2006-05-04 00:38:42.000000000 +0200 -@@ -205,6 +205,9 @@ - int (*transfer)(struct spi_device *spi, - struct spi_message *mesg); - -+ /* bidirectional bulk transfer, synchronous, non-sleeping */ -+ int (*transfer_nosleep)(struct spi_device *spi, -+ struct spi_message *mesg); - /* called on release() to free memory provided by spi_master */ - void (*cleanup)(const struct spi_device *spi); - }; -@@ -485,6 +488,16 @@ - return spi->master->transfer(spi, message); - } - -+static inline int -+spi_sync_nosleep(struct spi_device *spi, struct spi_message *msg) -+{ -+ if (!spi->master->transfer_nosleep) -+ return -EIO; -+ -+ msg->spi = master; -+ return spi->master->transfer_nosleep(spi, message); -+} -+ - /*---------------------------------------------------------------------------*/ - - /* All these synchronous SPI transfer routines are utilities layered |