Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile
[linux-2.6] / drivers / net / irda / mcp2120-sir.c
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
52 static int __init mcp2120_sir_init(void)
53 {
54         return irda_register_dongle(&mcp2120);
55 }
56
57 static void __exit mcp2120_sir_cleanup(void)
58 {
59         irda_unregister_dongle(&mcp2120);
60 }
61
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
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
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
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);