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