1/********************************************************************* 2 * 3 * 4 * Filename: mcp2120.c 5 * Version: 1.0 6 * Description: Implementation for the MCP2120 (Microchip) 7 * Status: Experimental. 8 * Author: Felix Tang (tangf@eyetap.org) 9 * Created at: Sun Mar 31 19:32:12 EST 2002 10 * Based on code by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 2002 Felix Tang, All Rights Reserved. 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License as 16 * published by the Free Software Foundation; either version 2 of 17 * the License, or (at your option) any later version. 18 * 19 ********************************************************************/ 20 21#include <linux/module.h> 22#include <linux/delay.h> 23#include <linux/init.h> 24 25#include <net/irda/irda.h> 26 27#include "sir-dev.h" 28 29static int mcp2120_reset(struct sir_dev *dev); 30static int mcp2120_open(struct sir_dev *dev); 31static int mcp2120_close(struct sir_dev *dev); 32static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed); 33 34#define MCP2120_9600 0x87 35#define MCP2120_19200 0x8B 36#define MCP2120_38400 0x85 37#define MCP2120_57600 0x83 38#define MCP2120_115200 0x81 39 40#define MCP2120_COMMIT 0x11 41 42static struct dongle_driver mcp2120 = { 43 .owner = THIS_MODULE, 44 .driver_name = "Microchip MCP2120", 45 .type = IRDA_MCP2120_DONGLE, 46 .open = mcp2120_open, 47 .close = mcp2120_close, 48 .reset = mcp2120_reset, 49 .set_speed = mcp2120_change_speed, 50}; 51 52static int __init mcp2120_sir_init(void) 53{ 54 return irda_register_dongle(&mcp2120); 55} 56 57static void __exit mcp2120_sir_cleanup(void) 58{ 59 irda_unregister_dongle(&mcp2120); 60} 61 62static int mcp2120_open(struct sir_dev *dev) 63{ 64 struct qos_info *qos = &dev->qos; 65 66 IRDA_DEBUG(2, "%s()\n", __FUNCTION__); 67 68 /* seems no explicit power-on required here and reset switching it on anyway */ 69 70 qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; 71 qos->min_turn_time.bits = 0x01; 72 irda_qos_bits_to_value(qos); 73 74 return 0; 75} 76 77static int mcp2120_close(struct sir_dev *dev) 78{ 79 IRDA_DEBUG(2, "%s()\n", __FUNCTION__); 80 81 /* Power off dongle */ 82 /* reset and inhibit mcp2120 */ 83 sirdev_set_dtr_rts(dev, TRUE, TRUE); 84 // sirdev_set_dtr_rts(dev, FALSE, FALSE); 85 86 return 0; 87} 88 89/* 90 * Function mcp2120_change_speed (dev, speed) 91 * 92 * Set the speed for the MCP2120. 93 * 94 */ 95 96#define MCP2120_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED+1) 97 98static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed) 99{ 100 unsigned state = dev->fsm.substate; 101 unsigned delay = 0; 102 u8 control[2]; 103 static int ret = 0; 104 105 IRDA_DEBUG(2, "%s()\n", __FUNCTION__); 106 107 switch (state) { 108 case SIRDEV_STATE_DONGLE_SPEED: 109 /* Set DTR to enter command mode */ 110 sirdev_set_dtr_rts(dev, TRUE, FALSE); 111 udelay(500); 112 113 ret = 0; 114 switch (speed) { 115 default: 116 speed = 9600; 117 ret = -EINVAL; 118 /* fall through */ 119 case 9600: 120 control[0] = MCP2120_9600; 121 //printk("mcp2120 9600\n"); 122 break; 123 case 19200: 124 control[0] = MCP2120_19200; 125 //printk("mcp2120 19200\n"); 126 break; 127 case 34800: 128 control[0] = MCP2120_38400; 129 //printk("mcp2120 38400\n"); 130 break; 131 case 57600: 132 control[0] = MCP2120_57600; 133 //printk("mcp2120 57600\n"); 134 break; 135 case 115200: 136 control[0] = MCP2120_115200; 137 //printk("mcp2120 115200\n"); 138 break; 139 } 140 control[1] = MCP2120_COMMIT; 141 142 /* Write control bytes */ 143 sirdev_raw_write(dev, control, 2); 144 dev->speed = speed; 145 146 state = MCP2120_STATE_WAIT_SPEED; 147 delay = 100; 148 //printk("mcp2120_change_speed: dongle_speed\n"); 149 break; 150 151 case MCP2120_STATE_WAIT_SPEED: 152 /* Go back to normal mode */ 153 sirdev_set_dtr_rts(dev, FALSE, FALSE); 154 //printk("mcp2120_change_speed: mcp_wait\n"); 155 break; 156 157 default: 158 IRDA_ERROR("%s(), undefine state %d\n", __FUNCTION__, state); 159 ret = -EINVAL; 160 break; 161 } 162 dev->fsm.substate = state; 163 return (delay > 0) ? delay : ret; 164} 165 166/* 167 * Function mcp2120_reset (driver) 168 * 169 * This function resets the mcp2120 dongle. 170 * 171 * Info: -set RTS to reset mcp2120 172 * -set DTR to set mcp2120 software command mode 173 * -mcp2120 defaults to 9600 baud after reset 174 * 175 * Algorithm: 176 * 0. Set RTS to reset mcp2120. 177 * 1. Clear RTS and wait for device reset timer of 30 ms (max). 178 * 179 */ 180 181#define MCP2120_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1) 182#define MCP2120_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2) 183 184static int mcp2120_reset(struct sir_dev *dev) 185{ 186 unsigned state = dev->fsm.substate; 187 unsigned delay = 0; 188 int ret = 0; 189 190 IRDA_DEBUG(2, "%s()\n", __FUNCTION__); 191 192 switch (state) { 193 case SIRDEV_STATE_DONGLE_RESET: 194 //printk("mcp2120_reset: dongle_reset\n"); 195 /* Reset dongle by setting RTS*/ 196 sirdev_set_dtr_rts(dev, TRUE, TRUE); 197 state = MCP2120_STATE_WAIT1_RESET; 198 delay = 50; 199 break; 200 201 case MCP2120_STATE_WAIT1_RESET: 202 //printk("mcp2120_reset: mcp2120_wait1\n"); 203 /* clear RTS and wait for at least 30 ms. */ 204 sirdev_set_dtr_rts(dev, FALSE, FALSE); 205 state = MCP2120_STATE_WAIT2_RESET; 206 delay = 50; 207 break; 208 209 case MCP2120_STATE_WAIT2_RESET: 210 //printk("mcp2120_reset mcp2120_wait2\n"); 211 /* Go back to normal mode */ 212 sirdev_set_dtr_rts(dev, FALSE, FALSE); 213 break; 214 215 default: 216 IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state); 217 ret = -EINVAL; 218 break; 219 } 220 dev->fsm.substate = state; 221 return (delay > 0) ? delay : ret; 222} 223 224MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>"); 225MODULE_DESCRIPTION("Microchip MCP2120"); 226MODULE_LICENSE("GPL"); 227MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */ 228 229module_init(mcp2120_sir_init); 230module_exit(mcp2120_sir_cleanup); 231