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 transceiver. 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#include <linux/sched.h> 124 125#include <net/irda/irda.h> 126 127#include "sir-dev.h" 128 129static int toim3232delay = 150; /* default is 150 ms */ 130module_param(toim3232delay, int, 0); 131MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); 132 133#if 0 134static int toim3232flipdtr = 0; /* default is DTR high to reset */ 135module_param(toim3232flipdtr, int, 0); 136MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)"); 137 138static int toim3232fliprts = 0; /* default is RTS high for baud change */ 139module_param(toim3232fliptrs, int, 0); 140MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)"); 141#endif 142 143static int toim3232_open(struct sir_dev *); 144static int toim3232_close(struct sir_dev *); 145static int toim3232_change_speed(struct sir_dev *, unsigned); 146static int toim3232_reset(struct sir_dev *); 147 148#define TOIM3232_115200 0x00 149#define TOIM3232_57600 0x01 150#define TOIM3232_38400 0x02 151#define TOIM3232_19200 0x03 152#define TOIM3232_9600 0x06 153#define TOIM3232_2400 0x0A 154 155#define TOIM3232_PW 0x10 /* Pulse select bit */ 156 157static struct dongle_driver toim3232 = { 158 .owner = THIS_MODULE, 159 .driver_name = "Vishay TOIM3232", 160 .type = IRDA_TOIM3232_DONGLE, 161 .open = toim3232_open, 162 .close = toim3232_close, 163 .reset = toim3232_reset, 164 .set_speed = toim3232_change_speed, 165}; 166 167static int __init toim3232_sir_init(void) 168{ 169 if (toim3232delay < 1 || toim3232delay > 500) 170 toim3232delay = 200; 171 pr_debug("%s - using %d ms delay\n", 172 toim3232.driver_name, toim3232delay); 173 return irda_register_dongle(&toim3232); 174} 175 176static void __exit toim3232_sir_cleanup(void) 177{ 178 irda_unregister_dongle(&toim3232); 179} 180 181static int toim3232_open(struct sir_dev *dev) 182{ 183 struct qos_info *qos = &dev->qos; 184 185 /* Pull the lines high to start with. 186 * 187 * For the IR320ST-2, we need to charge the main supply capacitor to 188 * switch the device on. We keep DTR high throughout to do this. 189 * When RTS, TD and RD are high, they will also trickle-charge the 190 * cap. RTS is high for data transmission, and low for baud rate select. 191 * -- DGB 192 */ 193 sirdev_set_dtr_rts(dev, TRUE, TRUE); 194 195 /* The TOI3232 supports many speeds between 1200bps and 115000bps. 196 * We really only care about those supported by the IRDA spec, but 197 * 38400 seems to be implemented in many places */ 198 qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; 199 200 /* From the tekram driver. Not sure what a reasonable value is -- DGB */ 201 qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ 202 irda_qos_bits_to_value(qos); 203 204 /* irda thread waits 50 msec for power settling */ 205 206 return 0; 207} 208 209static int toim3232_close(struct sir_dev *dev) 210{ 211 /* Power off dongle */ 212 sirdev_set_dtr_rts(dev, FALSE, FALSE); 213 214 return 0; 215} 216 217/* 218 * Function toim3232change_speed (dev, state, speed) 219 * 220 * Set the speed for the TOIM3232 based dongle. Warning, this 221 * function must be called with a process context! 222 * 223 * Algorithm 224 * 1. keep DTR high but clear RTS to bring into baud programming mode 225 * 2. wait at least 7us to enter programming mode 226 * 3. send control word to set baud rate and timing 227 * 4. wait at least 1us 228 * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver) 229 * 6. should take effect immediately (although probably worth waiting) 230 */ 231 232#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) 233 234static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) 235{ 236 unsigned state = dev->fsm.substate; 237 unsigned delay = 0; 238 u8 byte; 239 static int ret = 0; 240 241 switch(state) { 242 case SIRDEV_STATE_DONGLE_SPEED: 243 244 /* Figure out what we are going to send as a control byte */ 245 switch (speed) { 246 case 2400: 247 byte = TOIM3232_PW|TOIM3232_2400; 248 break; 249 default: 250 speed = 9600; 251 ret = -EINVAL; 252 /* fall thru */ 253 case 9600: 254 byte = TOIM3232_PW|TOIM3232_9600; 255 break; 256 case 19200: 257 byte = TOIM3232_PW|TOIM3232_19200; 258 break; 259 case 38400: 260 byte = TOIM3232_PW|TOIM3232_38400; 261 break; 262 case 57600: 263 byte = TOIM3232_PW|TOIM3232_57600; 264 break; 265 case 115200: 266 byte = TOIM3232_115200; 267 break; 268 } 269 270 /* Set DTR, Clear RTS: Go into baud programming mode */ 271 sirdev_set_dtr_rts(dev, TRUE, FALSE); 272 273 /* Wait at least 7us */ 274 udelay(14); 275 276 /* Write control byte */ 277 sirdev_raw_write(dev, &byte, 1); 278 279 dev->speed = speed; 280 281 state = TOIM3232_STATE_WAIT_SPEED; 282 delay = toim3232delay; 283 break; 284 285 case TOIM3232_STATE_WAIT_SPEED: 286 /* Have transmitted control byte * Wait for 'at least 1us' */ 287 udelay(14); 288 289 /* Set DTR, Set RTS: Go into normal data mode */ 290 sirdev_set_dtr_rts(dev, TRUE, TRUE); 291 292 /* Wait (TODO: check this is needed) */ 293 udelay(50); 294 break; 295 296 default: 297 printk(KERN_ERR "%s - undefined state %d\n", __func__, state); 298 ret = -EINVAL; 299 break; 300 } 301 302 dev->fsm.substate = state; 303 return (delay > 0) ? delay : ret; 304} 305 306/* 307 * Function toim3232reset (driver) 308 * 309 * This function resets the toim3232 dongle. Warning, this function 310 * must be called with a process context!! 311 * 312 * What we should do is: 313 * 0. Pull RESET high 314 * 1. Wait for at least 7us 315 * 2. Pull RESET low 316 * 3. Wait for at least 7us 317 * 4. Pull BR/~D high 318 * 5. Wait for at least 7us 319 * 6. Send control byte to set baud rate 320 * 7. Wait at least 1us after stop bit 321 * 8. Pull BR/~D low 322 * 9. Should then be in data mode 323 * 324 * Because the IR320ST-2 doesn't have the RESET line connected for some reason, 325 * we'll have to do something else. 326 * 327 * The default speed after a RESET is 9600, so lets try just bringing it up in 328 * data mode after switching it off, waiting for the supply capacitor to 329 * discharge, and then switch it back on. This isn't actually pulling RESET 330 * high, but it seems to have the same effect. 331 * 332 * This behaviour will probably work on dongles that have the RESET line connected, 333 * but if not, add a flag for the IR320ST-2, and implment the above-listed proper 334 * behaviour. 335 * 336 * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we 337 * need to have pull RTS low 338 */ 339 340static int toim3232_reset(struct sir_dev *dev) 341{ 342 /* Switch off both DTR and RTS to switch off dongle */ 343 sirdev_set_dtr_rts(dev, FALSE, FALSE); 344 345 /* Should sleep a while. This might be evil doing it this way.*/ 346 set_current_state(TASK_UNINTERRUPTIBLE); 347 schedule_timeout(msecs_to_jiffies(50)); 348 349 /* Set DTR, Set RTS (data mode) */ 350 sirdev_set_dtr_rts(dev, TRUE, TRUE); 351 352 /* Wait at least 10 ms for power to stabilize again */ 353 set_current_state(TASK_UNINTERRUPTIBLE); 354 schedule_timeout(msecs_to_jiffies(10)); 355 356 /* Speed should now be 9600 */ 357 dev->speed = 9600; 358 359 return 0; 360} 361 362MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>"); 363MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver"); 364MODULE_LICENSE("GPL"); 365MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */ 366 367module_init(toim3232_sir_init); 368module_exit(toim3232_sir_cleanup); 369