linux/drivers/net/irda/mcp2120-sir.c
<<
>>
Prefs
   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
  29static int mcp2120_reset(struct sir_dev *dev);
  30static int mcp2120_open(struct sir_dev *dev);
  31static int mcp2120_close(struct sir_dev *dev);
  32static 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
  42static 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
  52static int __init mcp2120_sir_init(void)
  53{
  54        return irda_register_dongle(&mcp2120);
  55}
  56
  57static void __exit mcp2120_sir_cleanup(void)
  58{
  59        irda_unregister_dongle(&mcp2120);
  60}
  61
  62static 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
  77static 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
  98static 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
 184static 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
 224MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
 225MODULE_DESCRIPTION("Microchip MCP2120");
 226MODULE_LICENSE("GPL");
 227MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
 228
 229module_init(mcp2120_sir_init);
 230module_exit(mcp2120_sir_cleanup);
 231