• 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 	IRDA_DEBUG(2, "%s()\n", __func__);
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 
mcp2120_close(struct sir_dev * dev)77 static int mcp2120_close(struct sir_dev *dev)
78 {
79 	IRDA_DEBUG(2, "%s()\n", __func__);
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 
mcp2120_change_speed(struct sir_dev * dev,unsigned speed)98 static 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", __func__);
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", __func__, 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 
mcp2120_reset(struct sir_dev * dev)184 static 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", __func__);
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", __func__, state);
217 		ret = -EINVAL;
218 		break;
219 	}
220 	dev->fsm.substate = state;
221 	return (delay > 0) ? delay : ret;
222 }
223 
224 MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
225 MODULE_DESCRIPTION("Microchip MCP2120");
226 MODULE_LICENSE("GPL");
227 MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
228 
229 module_init(mcp2120_sir_init);
230 module_exit(mcp2120_sir_cleanup);
231