1 /*********************************************************************
 
   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>
 
  12  *     Copyright (c) 2002 Felix Tang, All Rights Reserved.
 
  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.
 
  19  ********************************************************************/
 
  21 #include <linux/module.h>
 
  22 #include <linux/delay.h>
 
  23 #include <linux/init.h>
 
  25 #include <net/irda/irda.h>
 
  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);
 
  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
 
  40 #define MCP2120_COMMIT  0x11
 
  42 static struct dongle_driver mcp2120 = {
 
  44         .driver_name    = "Microchip MCP2120",
 
  45         .type           = IRDA_MCP2120_DONGLE,
 
  47         .close          = mcp2120_close,
 
  48         .reset          = mcp2120_reset,
 
  49         .set_speed      = mcp2120_change_speed,
 
  52 static int __init mcp2120_sir_init(void)
 
  54         return irda_register_dongle(&mcp2120);
 
  57 static void __exit mcp2120_sir_cleanup(void)
 
  59         irda_unregister_dongle(&mcp2120);
 
  62 static int mcp2120_open(struct sir_dev *dev)
 
  64         struct qos_info *qos = &dev->qos;
 
  66         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
  68         /* seems no explicit power-on required here and reset switching it on anyway */
 
  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);
 
  77 static int mcp2120_close(struct sir_dev *dev)
 
  79         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
  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);
 
  90  * Function mcp2120_change_speed (dev, speed)
 
  92  *    Set the speed for the MCP2120.
 
  96 #define MCP2120_STATE_WAIT_SPEED        (SIRDEV_STATE_DONGLE_SPEED+1)
 
  98 static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed)
 
 100         unsigned state = dev->fsm.substate;
 
 105         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 108         case SIRDEV_STATE_DONGLE_SPEED:
 
 109                 /* Set DTR to enter command mode */
 
 110                 sirdev_set_dtr_rts(dev, TRUE, FALSE);
 
 120                         control[0] = MCP2120_9600;
 
 121                         //printk("mcp2120 9600\n");
 
 124                         control[0] = MCP2120_19200;
 
 125                         //printk("mcp2120 19200\n");
 
 128                         control[0] = MCP2120_38400;
 
 129                         //printk("mcp2120 38400\n");
 
 132                         control[0] = MCP2120_57600;
 
 133                         //printk("mcp2120 57600\n");
 
 136                         control[0] = MCP2120_115200;
 
 137                         //printk("mcp2120 115200\n");
 
 140                 control[1] = MCP2120_COMMIT;
 
 142                 /* Write control bytes */
 
 143                 sirdev_raw_write(dev, control, 2);
 
 146                 state = MCP2120_STATE_WAIT_SPEED;
 
 148                 //printk("mcp2120_change_speed: dongle_speed\n");
 
 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");
 
 158                 IRDA_ERROR("%s(), undefine state %d\n", __FUNCTION__, state);
 
 162         dev->fsm.substate = state;
 
 163         return (delay > 0) ? delay : ret;
 
 167  * Function mcp2120_reset (driver)
 
 169  *      This function resets the mcp2120 dongle.
 
 171  *      Info: -set RTS to reset mcp2120
 
 172  *            -set DTR to set mcp2120 software command mode
 
 173  *            -mcp2120 defaults to 9600 baud after reset
 
 176  *      0. Set RTS to reset mcp2120.
 
 177  *      1. Clear RTS and wait for device reset timer of 30 ms (max).
 
 181 #define MCP2120_STATE_WAIT1_RESET       (SIRDEV_STATE_DONGLE_RESET+1)
 
 182 #define MCP2120_STATE_WAIT2_RESET       (SIRDEV_STATE_DONGLE_RESET+2)
 
 184 static int mcp2120_reset(struct sir_dev *dev)
 
 186         unsigned state = dev->fsm.substate;
 
 190         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 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;
 
 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;
 
 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);
 
 216                 IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state);
 
 220         dev->fsm.substate = state;
 
 221         return (delay > 0) ? delay : ret;
 
 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 */
 
 229 module_init(mcp2120_sir_init);
 
 230 module_exit(mcp2120_sir_cleanup);