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