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