• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 static int mcp2120_reset(struct sir_dev *dev);
30 static int mcp2120_open(struct sir_dev *dev);
31 static int mcp2120_close(struct sir_dev *dev);
32 static 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 
42 static 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 
mcp2120_sir_init(void)52 static int __init mcp2120_sir_init(void)
53 {
54 	return irda_register_dongle(&mcp2120);
55 }
56 
mcp2120_sir_cleanup(void)57 static void __exit mcp2120_sir_cleanup(void)
58 {
59 	irda_unregister_dongle(&mcp2120);
60 }
61 
mcp2120_open(struct sir_dev * dev)62 static int mcp2120_open(struct sir_dev *dev)
63 {
64 	struct qos_info *qos = &dev->qos;
65 
66 	/* seems no explicit power-on required here and reset switching it on anyway */
67 
68 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
69 	qos->min_turn_time.bits = 0x01;
70 	irda_qos_bits_to_value(qos);
71 
72 	return 0;
73 }
74 
mcp2120_close(struct sir_dev * dev)75 static int mcp2120_close(struct sir_dev *dev)
76 {
77 	/* Power off dongle */
78         /* reset and inhibit mcp2120 */
79 	sirdev_set_dtr_rts(dev, TRUE, TRUE);
80 	// sirdev_set_dtr_rts(dev, FALSE, FALSE);
81 
82 	return 0;
83 }
84 
85 /*
86  * Function mcp2120_change_speed (dev, speed)
87  *
88  *    Set the speed for the MCP2120.
89  *
90  */
91 
92 #define MCP2120_STATE_WAIT_SPEED	(SIRDEV_STATE_DONGLE_SPEED+1)
93 
mcp2120_change_speed(struct sir_dev * dev,unsigned speed)94 static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed)
95 {
96 	unsigned state = dev->fsm.substate;
97 	unsigned delay = 0;
98 	u8 control[2];
99 	static int ret = 0;
100 
101 	switch (state) {
102 	case SIRDEV_STATE_DONGLE_SPEED:
103 		/* Set DTR to enter command mode */
104 		sirdev_set_dtr_rts(dev, TRUE, FALSE);
105                 udelay(500);
106 
107 		ret = 0;
108 		switch (speed) {
109 		default:
110 			speed = 9600;
111 			ret = -EINVAL;
112 			/* fall through */
113 		case 9600:
114 			control[0] = MCP2120_9600;
115                         //printk("mcp2120 9600\n");
116 			break;
117 		case 19200:
118 			control[0] = MCP2120_19200;
119                         //printk("mcp2120 19200\n");
120 			break;
121 		case 34800:
122 			control[0] = MCP2120_38400;
123                         //printk("mcp2120 38400\n");
124 			break;
125 		case 57600:
126 			control[0] = MCP2120_57600;
127                         //printk("mcp2120 57600\n");
128 			break;
129 		case 115200:
130                         control[0] = MCP2120_115200;
131                         //printk("mcp2120 115200\n");
132 			break;
133 		}
134 		control[1] = MCP2120_COMMIT;
135 
136 		/* Write control bytes */
137 		sirdev_raw_write(dev, control, 2);
138 		dev->speed = speed;
139 
140 		state = MCP2120_STATE_WAIT_SPEED;
141 		delay = 100;
142                 //printk("mcp2120_change_speed: dongle_speed\n");
143 		break;
144 
145 	case MCP2120_STATE_WAIT_SPEED:
146 		/* Go back to normal mode */
147 		sirdev_set_dtr_rts(dev, FALSE, FALSE);
148                 //printk("mcp2120_change_speed: mcp_wait\n");
149 		break;
150 
151 	default:
152 		net_err_ratelimited("%s(), undefine state %d\n",
153 				    __func__, state);
154 		ret = -EINVAL;
155 		break;
156 	}
157 	dev->fsm.substate = state;
158 	return (delay > 0) ? delay : ret;
159 }
160 
161 /*
162  * Function mcp2120_reset (driver)
163  *
164  *      This function resets the mcp2120 dongle.
165  *
166  *      Info: -set RTS to reset mcp2120
167  *            -set DTR to set mcp2120 software command mode
168  *            -mcp2120 defaults to 9600 baud after reset
169  *
170  *      Algorithm:
171  *      0. Set RTS to reset mcp2120.
172  *      1. Clear RTS and wait for device reset timer of 30 ms (max).
173  *
174  */
175 
176 #define MCP2120_STATE_WAIT1_RESET	(SIRDEV_STATE_DONGLE_RESET+1)
177 #define MCP2120_STATE_WAIT2_RESET	(SIRDEV_STATE_DONGLE_RESET+2)
178 
mcp2120_reset(struct sir_dev * dev)179 static int mcp2120_reset(struct sir_dev *dev)
180 {
181 	unsigned state = dev->fsm.substate;
182 	unsigned delay = 0;
183 	int ret = 0;
184 
185 	switch (state) {
186 	case SIRDEV_STATE_DONGLE_RESET:
187                 //printk("mcp2120_reset: dongle_reset\n");
188 		/* Reset dongle by setting RTS*/
189 		sirdev_set_dtr_rts(dev, TRUE, TRUE);
190 		state = MCP2120_STATE_WAIT1_RESET;
191 		delay = 50;
192 		break;
193 
194 	case MCP2120_STATE_WAIT1_RESET:
195                 //printk("mcp2120_reset: mcp2120_wait1\n");
196                 /* clear RTS and wait for at least 30 ms. */
197 		sirdev_set_dtr_rts(dev, FALSE, FALSE);
198 		state = MCP2120_STATE_WAIT2_RESET;
199 		delay = 50;
200 		break;
201 
202 	case MCP2120_STATE_WAIT2_RESET:
203                 //printk("mcp2120_reset mcp2120_wait2\n");
204 		/* Go back to normal mode */
205 		sirdev_set_dtr_rts(dev, FALSE, FALSE);
206 		break;
207 
208 	default:
209 		net_err_ratelimited("%s(), undefined state %d\n",
210 				    __func__, state);
211 		ret = -EINVAL;
212 		break;
213 	}
214 	dev->fsm.substate = state;
215 	return (delay > 0) ? delay : ret;
216 }
217 
218 MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
219 MODULE_DESCRIPTION("Microchip MCP2120");
220 MODULE_LICENSE("GPL");
221 MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
222 
223 module_init(mcp2120_sir_init);
224 module_exit(mcp2120_sir_cleanup);
225