]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/ssi/omap-uwire.c
61b3ca16257e0fd2af63ce60851761ee6f91702d
[linux-2.6-omap-h63xx.git] / drivers / ssi / omap-uwire.c
1 /*
2  * BRIEF MODULE DESCRIPTION
3  *
4  *      uWire interface driver for the OMAP Platform
5  *
6  * Copyright 2003 MontaVista Software Inc.
7  * Author: MontaVista Software, Inc.
8  *         source@mvista.com
9  *
10  * Ported to 2.6 uwire interface.
11  * Copyright (C) 2004 Texas Instruments.
12  *
13  * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.com>
14  *
15  *  This program is free software; you can redistribute  it and/or modify it
16  *  under  the terms of  the GNU General  Public License as published by the
17  *  Free Software Foundation;  either version 2 of the  License, or (at your
18  *  option) any later version.
19  *
20  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
21  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
22  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
23  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
24  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
26  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
28  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  *  You should have received a copy of the  GNU General Public License along
32  *  with this program; if not, write  to the Free Software Foundation, Inc.,
33  *  675 Mass Ave, Cambridge, MA 02139, USA.
34  */
35
36 #include <linux/module.h>
37 #include <linux/init.h>
38 #include <linux/sched.h>
39 #include <linux/errno.h>
40 #include <linux/delay.h>
41
42 #include <asm/system.h>
43 #include <asm/irq.h>
44 #include <asm/hardware.h>
45 #include <asm/io.h>
46 #include <asm/mach-types.h>
47 #include <asm/arch/mux.h>
48 #include <asm/arch/omap730.h>   /* OMAP730_IO_CONF registers */
49
50 #include "omap-uwire.h"
51
52 /* uWire Registers: */
53 #define UWIRE_BASE    0xFFFB3000
54 #define UWIRE_IO_SIZE 0x20
55 #define UWIRE_TDR     0x00
56 #define UWIRE_RDR     0x00
57 #define UWIRE_CSR     0x01
58 #define UWIRE_SR1     0x02
59 #define UWIRE_SR2     0x03
60 #define UWIRE_SR3     0x04
61 #define UWIRE_SR4     0x05
62 #define UWIRE_SR5     0x06
63
64 static unsigned short uwire_flags[4];
65 static unsigned long uwire_base = io_p2v(UWIRE_BASE);
66 static spinlock_t uwire_lock;
67 static unsigned int uwire_idx_shift;
68
69 static inline void uwire_write_reg(int idx, u16 val)
70 {
71         __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
72 }
73
74 static inline u16 uwire_read_reg(int idx)
75 {
76         return __raw_readw(uwire_base + (idx << uwire_idx_shift));
77 }
78
79 void omap_uwire_configure_mode(int cs, unsigned long flags)
80 {
81         u16 w, val = 0;
82         int shift, reg;
83
84         BUG_ON(cs > 3);
85
86         val = flags & 0x3f;
87         if (flags & UWIRE_CLK_INVERTED)
88                 val ^= 0x03;
89         if (cs & 1)
90                 shift = 6;
91         else
92                 shift = 0;
93         if (cs <= 1)
94                 reg = UWIRE_SR1;
95         else
96                 reg = UWIRE_SR2;
97         spin_lock(&uwire_lock);
98         w = uwire_read_reg(reg);
99         w &= ~(0x3f << shift);
100         w |= val << shift;
101         uwire_write_reg(reg, w);
102         spin_unlock(&uwire_lock);
103
104         uwire_flags[cs] = flags;
105 }
106
107 static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
108 {
109         u16 w;
110         int c = 0;
111         unsigned long max_jiffies = jiffies + HZ;
112
113         for (;;) {
114                 w = uwire_read_reg(UWIRE_CSR);
115                 if ((w & mask) == val)
116                         break;
117                 if (time_after(jiffies, max_jiffies)) {
118                         printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n",
119                                __FUNCTION__, w, mask, val);
120                         return -1;
121                 }
122                 c++;
123                 if (might_not_catch && c > 64)
124                         break;
125         }
126         return 0;
127 }
128
129 int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size,
130                              u16 *rx_buf, int leave_cs_active)
131 {
132         u16 ret = -1, w;
133         u16 mask;
134
135         BUG_ON(cs > 3);
136         BUG_ON(rx_size && !rx_buf);
137
138         spin_lock(&uwire_lock);
139
140         if (wait_uwire_csr_flag(1 << 14, 0, 0))
141                 goto exit;
142
143         if (uwire_flags[cs] & UWIRE_CLK_INVERTED)
144                 uwire_write_reg(UWIRE_SR4, 1);
145         else
146                 uwire_write_reg(UWIRE_SR4, 0);
147
148         w = cs << 10;
149         w |= 1 << 12;                           /* CS_CMD : activate CS */
150         uwire_write_reg(UWIRE_CSR, w);
151
152         /* Shift data to 16bit MSb and place it in TX register. */
153         uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size));
154
155         if (wait_uwire_csr_flag(1 << 14, 0, 0))
156                 goto exit;
157
158         w = rx_size | (tx_size << 5) | (cs << 10);
159         w |= (1 << 12) | (1 << 13);
160         /* Start uWire read/write */
161         uwire_write_reg(UWIRE_CSR, w);
162
163         /* Wait till read/write actually starts.
164          * This is needed at high (>=60MHz) MPU frequencies
165          * REVISIT: But occasionally we won't have time to catch it
166          */
167         if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1))
168                 goto exit;
169
170         /* Wait for both transfers to be completed */
171         mask = 1 << 14;                 /* CSRB : reg busy */
172         w = 0;
173         if (rx_size) {
174                 mask |= 1 << 15;        /* RDRB : reg busy */
175                 w |= 1 << 15;
176         }
177
178         if (wait_uwire_csr_flag(mask, w, 0))
179                 goto exit;
180
181         if (rx_size)
182                 *rx_buf = uwire_read_reg(UWIRE_RDR);
183
184         if (!leave_cs_active)
185                 uwire_write_reg(UWIRE_CSR, cs << 10);
186
187         ret = 0;
188
189 exit:
190         spin_unlock(&uwire_lock);
191         return ret;
192 }
193
194 static int __init omap_uwire_init(void)
195 {
196         spin_lock_init(&uwire_lock);
197         if (cpu_is_omap730())
198                 uwire_idx_shift = 1;
199         else
200                 uwire_idx_shift = 2;
201
202         uwire_write_reg(UWIRE_SR3, 1);
203         if (machine_is_omap_h2()) {
204                 /* defaults: W21 SDO, U18 SDI, V19 SCL */
205                 omap_cfg_reg(N14_1610_UWIRE_CS0);
206                 omap_cfg_reg(N15_1610_UWIRE_CS1);
207         }
208         if (machine_is_omap_osk()) {
209                 /* this is the standard expansion connector usage, with
210                  * the other chipselect pins for MPUIO2 and MPUIO4.
211                  */
212                 omap_cfg_reg(N14_1610_UWIRE_CS0);
213                 omap_cfg_reg(P15_1610_UWIRE_CS3);
214         }
215         if (machine_is_omap_perseus2()) {
216                 /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
217                 int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
218                 omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
219         }
220         return 0;
221 }
222
223 static void __exit omap_uwire_exit(void)
224 {
225 }
226
227 subsys_initcall(omap_uwire_init);
228 module_exit(omap_uwire_exit);
229
230 EXPORT_SYMBOL(omap_uwire_configure_mode);
231 EXPORT_SYMBOL(omap_uwire_data_transfer);
232
233 MODULE_LICENSE("GPL");