Commit | Line | Data |
---|---|---|
69ebb222 KE |
1 | /** |
2 | * arch/arm/mac-sa1100/jornada720_ssp.c | |
3 | * | |
4 | * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> | |
5 | * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * SSP driver for the HP Jornada 710/720/728 | |
12 | */ | |
13 | ||
14 | #include <linux/delay.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/platform_device.h> | |
20 | #include <linux/sched.h> | |
3169663a | 21 | #include <linux/io.h> |
69ebb222 | 22 | |
a09e64fb | 23 | #include <mach/hardware.h> |
a09e64fb | 24 | #include <mach/jornada720.h> |
58005b32 | 25 | #include <asm/hardware/ssp.h> |
69ebb222 KE |
26 | |
27 | static DEFINE_SPINLOCK(jornada_ssp_lock); | |
28 | static unsigned long jornada_ssp_flags; | |
29 | ||
30 | /** | |
31 | * jornada_ssp_reverse - reverses input byte | |
32 | * | |
25985edc | 33 | * we need to reverse all data we receive from the mcu due to its physical location |
69ebb222 KE |
34 | * returns : 01110111 -> 11101110 |
35 | */ | |
36 | u8 inline jornada_ssp_reverse(u8 byte) | |
37 | { | |
38 | return | |
39 | ((0x80 & byte) >> 7) | | |
40 | ((0x40 & byte) >> 5) | | |
41 | ((0x20 & byte) >> 3) | | |
42 | ((0x10 & byte) >> 1) | | |
43 | ((0x08 & byte) << 1) | | |
44 | ((0x04 & byte) << 3) | | |
45 | ((0x02 & byte) << 5) | | |
46 | ((0x01 & byte) << 7); | |
47 | }; | |
48 | EXPORT_SYMBOL(jornada_ssp_reverse); | |
49 | ||
50 | /** | |
51 | * jornada_ssp_byte - waits for ready ssp bus and sends byte | |
52 | * | |
53 | * waits for fifo buffer to clear and then transmits, if it doesn't then we will | |
54 | * timeout after <timeout> rounds. Needs mcu running before its called. | |
55 | * | |
56 | * returns : %mcu output on success | |
3ac49a1c | 57 | * : %-ETIMEDOUT on timeout |
69ebb222 KE |
58 | */ |
59 | int jornada_ssp_byte(u8 byte) | |
60 | { | |
61 | int timeout = 400000; | |
62 | u16 ret; | |
63 | ||
64 | while ((GPLR & GPIO_GPIO10)) { | |
65 | if (!--timeout) { | |
66 | printk(KERN_WARNING "SSP: timeout while waiting for transmit\n"); | |
67 | return -ETIMEDOUT; | |
68 | } | |
69 | cpu_relax(); | |
70 | } | |
71 | ||
72 | ret = jornada_ssp_reverse(byte) << 8; | |
73 | ||
74 | ssp_write_word(ret); | |
75 | ssp_read_word(&ret); | |
76 | ||
77 | return jornada_ssp_reverse(ret); | |
78 | }; | |
79 | EXPORT_SYMBOL(jornada_ssp_byte); | |
80 | ||
81 | /** | |
82 | * jornada_ssp_inout - decide if input is command or trading byte | |
83 | * | |
84 | * returns : (jornada_ssp_byte(byte)) on success | |
3ac49a1c | 85 | * : %-ETIMEDOUT on timeout failure |
69ebb222 KE |
86 | */ |
87 | int jornada_ssp_inout(u8 byte) | |
88 | { | |
89 | int ret, i; | |
90 | ||
91 | /* true means command byte */ | |
92 | if (byte != TXDUMMY) { | |
93 | ret = jornada_ssp_byte(byte); | |
94 | /* Proper return to commands is TxDummy */ | |
95 | if (ret != TXDUMMY) { | |
96 | for (i = 0; i < 256; i++)/* flushing bus */ | |
97 | if (jornada_ssp_byte(TXDUMMY) == -1) | |
98 | break; | |
99 | return -ETIMEDOUT; | |
100 | } | |
101 | } else /* Exchange TxDummy for data */ | |
102 | ret = jornada_ssp_byte(TXDUMMY); | |
103 | ||
104 | return ret; | |
105 | }; | |
106 | EXPORT_SYMBOL(jornada_ssp_inout); | |
107 | ||
108 | /** | |
109 | * jornada_ssp_start - enable mcu | |
110 | * | |
111 | */ | |
58005b32 | 112 | void jornada_ssp_start(void) |
69ebb222 KE |
113 | { |
114 | spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags); | |
115 | GPCR = GPIO_GPIO25; | |
116 | udelay(50); | |
58005b32 | 117 | return; |
69ebb222 KE |
118 | }; |
119 | EXPORT_SYMBOL(jornada_ssp_start); | |
120 | ||
121 | /** | |
122 | * jornada_ssp_end - disable mcu and turn off lock | |
123 | * | |
124 | */ | |
58005b32 | 125 | void jornada_ssp_end(void) |
69ebb222 KE |
126 | { |
127 | GPSR = GPIO_GPIO25; | |
128 | spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags); | |
58005b32 | 129 | return; |
69ebb222 KE |
130 | }; |
131 | EXPORT_SYMBOL(jornada_ssp_end); | |
132 | ||
91a99dfc | 133 | static int __devinit jornada_ssp_probe(struct platform_device *dev) |
69ebb222 KE |
134 | { |
135 | int ret; | |
136 | ||
137 | GPSR = GPIO_GPIO25; | |
138 | ||
139 | ret = ssp_init(); | |
140 | ||
141 | /* worked fine, lets not bother with anything else */ | |
142 | if (!ret) { | |
143 | printk(KERN_INFO "SSP: device initialized with irq\n"); | |
144 | return ret; | |
145 | } | |
146 | ||
147 | printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n"); | |
148 | ||
149 | /* init of Serial 4 port */ | |
150 | Ser4MCCR0 = 0; | |
151 | Ser4SSCR0 = 0x0387; | |
152 | Ser4SSCR1 = 0x18; | |
153 | ||
154 | /* clear out any left over data */ | |
155 | ssp_flush(); | |
156 | ||
157 | /* enable MCU */ | |
158 | jornada_ssp_start(); | |
159 | ||
160 | /* see if return value makes sense */ | |
161 | ret = jornada_ssp_inout(GETBRIGHTNESS); | |
162 | ||
163 | /* seems like it worked, just feed it with TxDummy to get rid of data */ | |
219e3dcd | 164 | if (ret == TXDUMMY) |
69ebb222 KE |
165 | jornada_ssp_inout(TXDUMMY); |
166 | ||
167 | jornada_ssp_end(); | |
168 | ||
169 | /* failed, lets just kill everything */ | |
170 | if (ret == -ETIMEDOUT) { | |
171 | printk(KERN_WARNING "SSP: attempts failed, bailing\n"); | |
172 | ssp_exit(); | |
173 | return -ENODEV; | |
174 | } | |
175 | ||
176 | /* all fine */ | |
177 | printk(KERN_INFO "SSP: device initialized\n"); | |
178 | return 0; | |
179 | }; | |
180 | ||
181 | static int jornada_ssp_remove(struct platform_device *dev) | |
182 | { | |
25985edc | 183 | /* Note that this doesn't actually remove the driver, since theres nothing to remove |
69ebb222 KE |
184 | * It just makes sure everything is turned off */ |
185 | GPSR = GPIO_GPIO25; | |
186 | ssp_exit(); | |
187 | return 0; | |
188 | }; | |
189 | ||
190 | struct platform_driver jornadassp_driver = { | |
191 | .probe = jornada_ssp_probe, | |
192 | .remove = jornada_ssp_remove, | |
193 | .driver = { | |
194 | .name = "jornada_ssp", | |
195 | }, | |
196 | }; | |
197 | ||
198 | static int __init jornada_ssp_init(void) | |
199 | { | |
200 | return platform_driver_register(&jornadassp_driver); | |
201 | } | |
b3945bcb LW |
202 | |
203 | module_init(jornada_ssp_init); |