Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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         /* 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
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
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
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);