diff options
author | David Basden <davidb-irda@rcpt.to> | 2006-03-21 01:21:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-21 01:21:10 -0500 |
commit | 0ac81ae34ec8898e7eb1388fe21e3cee7b626a88 (patch) | |
tree | a12010186c97a515d7484c827df030cd11ac4911 /drivers/net/irda/toim3232-sir.c | |
parent | 65a3980e6b14d591e3b8f5cdc7219be99e3003a4 (diff) |
[IRDA]: TOIM3232 dongle support
Here goes a patch for supporting TOIM3232 based serial IrDA dongles.
The code is based on the tekram dongle code.
It's been tested with a TOIM3232 based IRWave 320S dongle. It may work
for TOIM4232 dongles, although it's not been tested.
Signed-off-by: David Basden <davidb-irda@rcpt.to>
Signed-off-by: Samuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/irda/toim3232-sir.c')
-rw-r--r-- | drivers/net/irda/toim3232-sir.c | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c new file mode 100644 index 000000000000..f6e5fed6a36d --- /dev/null +++ b/drivers/net/irda/toim3232-sir.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: toim3232-sir.c | ||
4 | * Version: 1.0 | ||
5 | * Description: Implementation of dongles based on the Vishay/Temic | ||
6 | * TOIM3232 SIR Endec chipset. Currently only the | ||
7 | * IRWave IR320ST-2 is tested, although it should work | ||
8 | * with any TOIM3232 or TOIM4232 chipset based RS232 | ||
9 | * dongle with minimal modification. | ||
10 | * Based heavily on the Tekram driver (tekram.c), | ||
11 | * with thanks to Dag Brattli and Martin Diehl. | ||
12 | * Status: Experimental. | ||
13 | * Author: David Basden <davidb-irda@rcpt.to> | ||
14 | * Created at: Thu Feb 09 23:47:32 2006 | ||
15 | * | ||
16 | * Copyright (c) 2006 David Basden. | ||
17 | * Copyright (c) 1998-1999 Dag Brattli, | ||
18 | * Copyright (c) 2002 Martin Diehl, | ||
19 | * All Rights Reserved. | ||
20 | * | ||
21 | * This program is free software; you can redistribute it and/or | ||
22 | * modify it under the terms of the GNU General Public License as | ||
23 | * published by the Free Software Foundation; either version 2 of | ||
24 | * the License, or (at your option) any later version. | ||
25 | * | ||
26 | * Neither Dag Brattli nor University of Tromsø admit liability nor | ||
27 | * provide warranty for any of this software. This material is | ||
28 | * provided "AS-IS" and at no charge. | ||
29 | * | ||
30 | ********************************************************************/ | ||
31 | |||
32 | /* | ||
33 | * This driver has currently only been tested on the IRWave IR320ST-2 | ||
34 | * | ||
35 | * PROTOCOL: | ||
36 | * | ||
37 | * The protocol for talking to the TOIM3232 is quite easy, and is | ||
38 | * designed to interface with RS232 with only level convertors. The | ||
39 | * BR/~D line on the chip is brought high to signal 'command mode', | ||
40 | * where a command byte is sent to select the baudrate of the RS232 | ||
41 | * interface and the pulse length of the IRDA output. When BR/~D | ||
42 | * is brought low, the dongle then changes to the selected baudrate, | ||
43 | * and the RS232 interface is used for data until BR/~D is brought | ||
44 | * high again. The initial speed for the TOIMx323 after RESET is | ||
45 | * 9600 baud. The baudrate for command-mode is the last selected | ||
46 | * baud-rate, or 9600 after a RESET. | ||
47 | * | ||
48 | * The dongle I have (below) adds some extra hardware on the front end, | ||
49 | * but this is mostly directed towards pariasitic power from the RS232 | ||
50 | * line rather than changing very much about how to communicate with | ||
51 | * the TOIM3232. | ||
52 | * | ||
53 | * The protocol to talk to the TOIM4232 chipset seems to be almost | ||
54 | * identical to the TOIM3232 (and the 4232 datasheet is more detailed) | ||
55 | * so this code will probably work on that as well, although I haven't | ||
56 | * tested it on that hardware. | ||
57 | * | ||
58 | * Target dongle variations that might be common: | ||
59 | * | ||
60 | * DTR and RTS function: | ||
61 | * The data sheet for the 4232 has a sample implementation that hooks the | ||
62 | * DTR and RTS lines to the RESET and BaudRate/~Data lines of the | ||
63 | * chip (through line-converters). Given both DTR and RTS would have to | ||
64 | * be held low in normal operation, and the TOIMx232 requires +5V to | ||
65 | * signal ground, most dongle designers would almost certainly choose | ||
66 | * an implementation that kept at least one of DTR or RTS high in | ||
67 | * normal operation to provide power to the dongle, but will likely | ||
68 | * vary between designs. | ||
69 | * | ||
70 | * User specified command bits: | ||
71 | * There are two user-controllable output lines from the TOIMx232 that | ||
72 | * can be set low or high by setting the appropriate bits in the | ||
73 | * high-nibble of the command byte (when setting speed and pulse length). | ||
74 | * These might be used to switch on and off added hardware or extra | ||
75 | * dongle features. | ||
76 | * | ||
77 | * | ||
78 | * Target hardware: IRWave IR320ST-2 | ||
79 | * | ||
80 | * The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic | ||
81 | * TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transciever. | ||
82 | * It uses a hex inverter and some discrete components to buffer and | ||
83 | * line convert the RS232 down to 5V. | ||
84 | * | ||
85 | * The dongle is powered through a voltage regulator, fed by a large | ||
86 | * capacitor. To switch the dongle on, DTR is brought high to charge | ||
87 | * the capacitor and drive the voltage regulator. DTR isn't associated | ||
88 | * with any control lines on the TOIM3232. Parisitic power is also taken | ||
89 | * from the RTS, TD and RD lines when brought high, but through resistors. | ||
90 | * When DTR is low, the circuit might lose power even with RTS high. | ||
91 | * | ||
92 | * RTS is inverted and attached to the BR/~D input pin. When RTS | ||
93 | * is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode. | ||
94 | * RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command | ||
95 | * mode'. | ||
96 | * | ||
97 | * For some unknown reason, the RESET line isn't actually connected | ||
98 | * to anything. This means to reset the dongle to get it to a known | ||
99 | * state (9600 baud) you must drop DTR and RTS low, wait for the power | ||
100 | * capacitor to discharge, and then bring DTR (and RTS for data mode) | ||
101 | * high again, and wait for the capacitor to charge, the power supply | ||
102 | * to stabilise, and the oscillator clock to stabilise. | ||
103 | * | ||
104 | * Fortunately, if the current baudrate is known, the chipset can | ||
105 | * easily change speed by entering command mode without having to | ||
106 | * reset the dongle first. | ||
107 | * | ||
108 | * Major Components: | ||
109 | * | ||
110 | * - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings | ||
111 | * to IRDA pulse timings | ||
112 | * - 3.6864MHz crystal to drive TOIM3232 clock oscillator | ||
113 | * - DM74lS04M Inverting Hex line buffer for RS232 input buffering | ||
114 | * and level conversion | ||
115 | * - PJ2951AC 150mA voltage regulator | ||
116 | * - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver | ||
117 | * | ||
118 | */ | ||
119 | |||
120 | #include <linux/module.h> | ||
121 | #include <linux/delay.h> | ||
122 | #include <linux/init.h> | ||
123 | |||
124 | #include <net/irda/irda.h> | ||
125 | |||
126 | #include "sir-dev.h" | ||
127 | |||
128 | MODULE_PARM(toim3232delay, "i"); | ||
129 | MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); | ||
130 | static int toim3232delay = 150; /* default is 150 ms */ | ||
131 | |||
132 | #if 0 | ||
133 | MODULE_PARM(toim3232flipdtr, "i"); | ||
134 | MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)"); | ||
135 | static int toim3232flipdtr = 0; /* default is DTR high to reset */ | ||
136 | |||
137 | MODULE_PARM(toim3232fliptrs, "i"); | ||
138 | MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)"); | ||
139 | static int toim3232fliprts = 0; /* default is RTS high for baud change */ | ||
140 | #endif | ||
141 | |||
142 | static int toim3232_open(struct sir_dev *); | ||
143 | static int toim3232_close(struct sir_dev *); | ||
144 | static int toim3232_change_speed(struct sir_dev *, unsigned); | ||
145 | static int toim3232_reset(struct sir_dev *); | ||
146 | |||
147 | #define TOIM3232_115200 0x00 | ||
148 | #define TOIM3232_57600 0x01 | ||
149 | #define TOIM3232_38400 0x02 | ||
150 | #define TOIM3232_19200 0x03 | ||
151 | #define TOIM3232_9600 0x06 | ||
152 | #define TOIM3232_2400 0x0A | ||
153 | |||
154 | #define TOIM3232_PW 0x10 /* Pulse select bit */ | ||
155 | |||
156 | static struct dongle_driver toim3232 = { | ||
157 | .owner = THIS_MODULE, | ||
158 | .driver_name = "Vishay TOIM3232", | ||
159 | .type = IRDA_TOIM3232_DONGLE, | ||
160 | .open = toim3232_open, | ||
161 | .close = toim3232_close, | ||
162 | .reset = toim3232_reset, | ||
163 | .set_speed = toim3232_change_speed, | ||
164 | }; | ||
165 | |||
166 | static int __init toim3232_sir_init(void) | ||
167 | { | ||
168 | if (toim3232delay < 1 || toim3232delay > 500) | ||
169 | toim3232delay = 200; | ||
170 | IRDA_DEBUG(1, "%s - using %d ms delay\n", | ||
171 | toim3232.driver_name, toim3232delay); | ||
172 | return irda_register_dongle(&toim3232); | ||
173 | } | ||
174 | |||
175 | static void __exit toim3232_sir_cleanup(void) | ||
176 | { | ||
177 | irda_unregister_dongle(&toim3232); | ||
178 | } | ||
179 | |||
180 | static int toim3232_open(struct sir_dev *dev) | ||
181 | { | ||
182 | struct qos_info *qos = &dev->qos; | ||
183 | |||
184 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
185 | |||
186 | /* Pull the lines high to start with. | ||
187 | * | ||
188 | * For the IR320ST-2, we need to charge the main supply capacitor to | ||
189 | * switch the device on. We keep DTR high throughout to do this. | ||
190 | * When RTS, TD and RD are high, they will also trickle-charge the | ||
191 | * cap. RTS is high for data transmission, and low for baud rate select. | ||
192 | * -- DGB | ||
193 | */ | ||
194 | sirdev_set_dtr_rts(dev, TRUE, TRUE); | ||
195 | |||
196 | /* The TOI3232 supports many speeds between 1200bps and 115000bps. | ||
197 | * We really only care about those supported by the IRDA spec, but | ||
198 | * 38400 seems to be implemented in many places */ | ||
199 | qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; | ||
200 | |||
201 | /* From the tekram driver. Not sure what a reasonable value is -- DGB */ | ||
202 | qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ | ||
203 | irda_qos_bits_to_value(qos); | ||
204 | |||
205 | /* irda thread waits 50 msec for power settling */ | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int toim3232_close(struct sir_dev *dev) | ||
211 | { | ||
212 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
213 | |||
214 | /* Power off dongle */ | ||
215 | sirdev_set_dtr_rts(dev, FALSE, FALSE); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Function toim3232change_speed (dev, state, speed) | ||
222 | * | ||
223 | * Set the speed for the TOIM3232 based dongle. Warning, this | ||
224 | * function must be called with a process context! | ||
225 | * | ||
226 | * Algorithm | ||
227 | * 1. keep DTR high but clear RTS to bring into baud programming mode | ||
228 | * 2. wait at least 7us to enter programming mode | ||
229 | * 3. send control word to set baud rate and timing | ||
230 | * 4. wait at least 1us | ||
231 | * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver) | ||
232 | * 6. should take effect immediately (although probably worth waiting) | ||
233 | */ | ||
234 | |||
235 | #define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) | ||
236 | |||
237 | static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) | ||
238 | { | ||
239 | unsigned state = dev->fsm.substate; | ||
240 | unsigned delay = 0; | ||
241 | u8 byte; | ||
242 | static int ret = 0; | ||
243 | |||
244 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
245 | |||
246 | switch(state) { | ||
247 | case SIRDEV_STATE_DONGLE_SPEED: | ||
248 | |||
249 | /* Figure out what we are going to send as a control byte */ | ||
250 | switch (speed) { | ||
251 | case 2400: | ||
252 | byte = TOIM3232_PW|TOIM3232_2400; | ||
253 | break; | ||
254 | default: | ||
255 | speed = 9600; | ||
256 | ret = -EINVAL; | ||
257 | /* fall thru */ | ||
258 | case 9600: | ||
259 | byte = TOIM3232_PW|TOIM3232_9600; | ||
260 | break; | ||
261 | case 19200: | ||
262 | byte = TOIM3232_PW|TOIM3232_19200; | ||
263 | break; | ||
264 | case 38400: | ||
265 | byte = TOIM3232_PW|TOIM3232_38400; | ||
266 | break; | ||
267 | case 57600: | ||
268 | byte = TOIM3232_PW|TOIM3232_57600; | ||
269 | break; | ||
270 | case 115200: | ||
271 | byte = TOIM3232_115200; | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | /* Set DTR, Clear RTS: Go into baud programming mode */ | ||
276 | sirdev_set_dtr_rts(dev, TRUE, FALSE); | ||
277 | |||
278 | /* Wait at least 7us */ | ||
279 | udelay(14); | ||
280 | |||
281 | /* Write control byte */ | ||
282 | sirdev_raw_write(dev, &byte, 1); | ||
283 | |||
284 | dev->speed = speed; | ||
285 | |||
286 | state = TOIM3232_STATE_WAIT_SPEED; | ||
287 | delay = toim3232delay; | ||
288 | break; | ||
289 | |||
290 | case TOIM3232_STATE_WAIT_SPEED: | ||
291 | /* Have transmitted control byte * Wait for 'at least 1us' */ | ||
292 | udelay(14); | ||
293 | |||
294 | /* Set DTR, Set RTS: Go into normal data mode */ | ||
295 | sirdev_set_dtr_rts(dev, TRUE, TRUE); | ||
296 | |||
297 | /* Wait (TODO: check this is needed) */ | ||
298 | udelay(50); | ||
299 | break; | ||
300 | |||
301 | default: | ||
302 | printk(KERN_ERR "%s - undefined state %d\n", __FUNCTION__, state); | ||
303 | ret = -EINVAL; | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | dev->fsm.substate = state; | ||
308 | return (delay > 0) ? delay : ret; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Function toim3232reset (driver) | ||
313 | * | ||
314 | * This function resets the toim3232 dongle. Warning, this function | ||
315 | * must be called with a process context!! | ||
316 | * | ||
317 | * What we should do is: | ||
318 | * 0. Pull RESET high | ||
319 | * 1. Wait for at least 7us | ||
320 | * 2. Pull RESET low | ||
321 | * 3. Wait for at least 7us | ||
322 | * 4. Pull BR/~D high | ||
323 | * 5. Wait for at least 7us | ||
324 | * 6. Send control byte to set baud rate | ||
325 | * 7. Wait at least 1us after stop bit | ||
326 | * 8. Pull BR/~D low | ||
327 | * 9. Should then be in data mode | ||
328 | * | ||
329 | * Because the IR320ST-2 doesn't have the RESET line connected for some reason, | ||
330 | * we'll have to do something else. | ||
331 | * | ||
332 | * The default speed after a RESET is 9600, so lets try just bringing it up in | ||
333 | * data mode after switching it off, waiting for the supply capacitor to | ||
334 | * discharge, and then switch it back on. This isn't actually pulling RESET | ||
335 | * high, but it seems to have the same effect. | ||
336 | * | ||
337 | * This behaviour will probably work on dongles that have the RESET line connected, | ||
338 | * but if not, add a flag for the IR320ST-2, and implment the above-listed proper | ||
339 | * behaviour. | ||
340 | * | ||
341 | * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we | ||
342 | * need to have pull RTS low | ||
343 | */ | ||
344 | |||
345 | static int toim3232_reset(struct sir_dev *dev) | ||
346 | { | ||
347 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
348 | |||
349 | /* Switch off both DTR and RTS to switch off dongle */ | ||
350 | sirdev_set_dtr_rts(dev, FALSE, FALSE); | ||
351 | |||
352 | /* Should sleep a while. This might be evil doing it this way.*/ | ||
353 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
354 | schedule_timeout(msecs_to_jiffies(50)); | ||
355 | |||
356 | /* Set DTR, Set RTS (data mode) */ | ||
357 | sirdev_set_dtr_rts(dev, TRUE, TRUE); | ||
358 | |||
359 | /* Wait at least 10 ms for power to stabilize again */ | ||
360 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
361 | schedule_timeout(msecs_to_jiffies(10)); | ||
362 | |||
363 | /* Speed should now be 9600 */ | ||
364 | dev->speed = 9600; | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>"); | ||
370 | MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver"); | ||
371 | MODULE_LICENSE("GPL"); | ||
372 | MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */ | ||
373 | |||
374 | module_init(toim3232_sir_init); | ||
375 | module_exit(toim3232_sir_cleanup); | ||