1/* 2 * linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c 3 * Copyright (C) 2000-2001 Toshiba Corporation 4 * 5 * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the 6 * terms of the GNU General Public License version 2. This program is 7 * licensed "as is" without any warranty of any kind, whether express 8 * or implied. 9 * 10 * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) 11 */ 12#include <linux/init.h> 13#include <linux/delay.h> 14#include <linux/errno.h> 15#include <linux/interrupt.h> 16#include <linux/module.h> 17#include <linux/sched.h> 18#include <linux/spinlock.h> 19#include <linux/wait.h> 20#include <asm/tx4938/spi.h> 21#include <asm/tx4938/tx4938.h> 22 23static int (*txx9_spi_cs_func)(int chipid, int on); 24static DEFINE_SPINLOCK(txx9_spi_lock); 25 26extern unsigned int txx9_gbus_clock; 27 28#define SPI_FIFO_SIZE 4 29 30void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on)) 31{ 32 txx9_spi_cs_func = cs_func; 33 /* enter config mode */ 34 tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; 35} 36 37static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait); 38 39static irqreturn_t txx9_spi_interrupt(int irq, void *dev_id) 40{ 41 /* disable rx intr */ 42 tx4938_spiptr->cr0 &= ~TXx9_SPCR0_RBSIE; 43 wake_up(&txx9_spi_wait); 44 45 return IRQ_HANDLED; 46} 47 48static struct irqaction txx9_spi_action = { 49 .handler = txx9_spi_interrupt, 50 .name = "spi", 51}; 52 53void __init txx9_spi_irqinit(int irc_irq) 54{ 55 setup_irq(irc_irq, &txx9_spi_action); 56} 57 58int txx9_spi_io(int chipid, struct spi_dev_desc *desc, 59 unsigned char **inbufs, unsigned int *incounts, 60 unsigned char **outbufs, unsigned int *outcounts, 61 int cansleep) 62{ 63 unsigned int incount, outcount; 64 unsigned char *inp, *outp; 65 int ret; 66 unsigned long flags; 67 68 spin_lock_irqsave(&txx9_spi_lock, flags); 69 if ((tx4938_spiptr->mcr & TXx9_SPMCR_OPMODE) == TXx9_SPMCR_ACTIVE) { 70 spin_unlock_irqrestore(&txx9_spi_lock, flags); 71 return -EBUSY; 72 } 73 /* enter config mode */ 74 tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; 75 tx4938_spiptr->cr0 = 76 (desc->byteorder ? TXx9_SPCR0_SBOS : 0) | 77 (desc->polarity ? TXx9_SPCR0_SPOL : 0) | 78 (desc->phase ? TXx9_SPCR0_SPHA : 0) | 79 0x08; 80 tx4938_spiptr->cr1 = 81 (((TXX9_IMCLK + desc->baud) / (2 * desc->baud) - 1) << 8) | 82 0x08 /* 8 bit only */; 83 /* enter active mode */ 84 tx4938_spiptr->mcr = TXx9_SPMCR_ACTIVE; 85 spin_unlock_irqrestore(&txx9_spi_lock, flags); 86 87 /* CS ON */ 88 if ((ret = txx9_spi_cs_func(chipid, 1)) < 0) { 89 spin_unlock_irqrestore(&txx9_spi_lock, flags); 90 return ret; 91 } 92 udelay(desc->tcss); 93 94 /* do scatter IO */ 95 inp = inbufs ? *inbufs : NULL; 96 outp = outbufs ? *outbufs : NULL; 97 incount = 0; 98 outcount = 0; 99 while (1) { 100 unsigned char data; 101 unsigned int count; 102 int i; 103 if (!incount) { 104 incount = incounts ? *incounts++ : 0; 105 inp = (incount && inbufs) ? *inbufs++ : NULL; 106 } 107 if (!outcount) { 108 outcount = outcounts ? *outcounts++ : 0; 109 outp = (outcount && outbufs) ? *outbufs++ : NULL; 110 } 111 if (!inp && !outp) 112 break; 113 count = SPI_FIFO_SIZE; 114 if (incount) 115 count = min(count, incount); 116 if (outcount) 117 count = min(count, outcount); 118 119 /* now tx must be idle... */ 120 while (!(tx4938_spiptr->sr & TXx9_SPSR_SIDLE)) 121 ; 122 123 tx4938_spiptr->cr0 = 124 (tx4938_spiptr->cr0 & ~TXx9_SPCR0_RXIFL_MASK) | 125 ((count - 1) << 12); 126 if (cansleep) { 127 /* enable rx intr */ 128 tx4938_spiptr->cr0 |= TXx9_SPCR0_RBSIE; 129 } 130 /* send */ 131 for (i = 0; i < count; i++) 132 tx4938_spiptr->dr = inp ? *inp++ : 0; 133 /* wait all rx data */ 134 if (cansleep) { 135 wait_event(txx9_spi_wait, 136 tx4938_spiptr->sr & TXx9_SPSR_SRRDY); 137 } else { 138 while (!(tx4938_spiptr->sr & TXx9_SPSR_RBSI)) 139 ; 140 } 141 /* receive */ 142 for (i = 0; i < count; i++) { 143 data = tx4938_spiptr->dr; 144 if (outp) 145 *outp++ = data; 146 } 147 if (incount) 148 incount -= count; 149 if (outcount) 150 outcount -= count; 151 } 152 153 /* CS OFF */ 154 udelay(desc->tcsh); 155 txx9_spi_cs_func(chipid, 0); 156 udelay(desc->tcsr); 157 158 spin_lock_irqsave(&txx9_spi_lock, flags); 159 /* enter config mode */ 160 tx4938_spiptr->mcr = TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR; 161 spin_unlock_irqrestore(&txx9_spi_lock, flags); 162 163 return 0; 164} 165