zoukankan      html  css  js  c++  java
  • Examples

    本文主要是学习gpio模拟mdc/mdio通信。

    运行环境是在ATMEL的sama5d35MCU,两个GPIO引脚模拟MDC/MDIO通信,读取百兆phy的寄存器的值。

      1 #include<linux/init.h>
      2 #include<linux/module.h>
      3 #include<linux/kernel.h>
      4 #include<linux/sched.h>
      5 #include<linux/init.h>
      6 #include<linux/sched.h>
      7 #include<linux/completion.h>
      8 #include <asm/system.h>
      9 #include <linux/param.h>
     10 #include<linux/gpio.h>
     11 #include<linux/cdev.h>
     12 #include<linux/fs.h>
     13 #include<linux/device.h>
     14 #include<linux/slab.h>
     15 #include<asm/uaccess.h>
     16 #include<linux/delay.h>
     17 #include<linux/miscdevice.h>
     18 
     19 
     20 /* bb:bit-bang,通过gpio引脚,用软件模拟通信*/
     21 
     22 #define MDIO 117  /* MDIO correspond PD21 */
     23 #define MDC 116  /* MDC correspond PD20 */
     24 #define MDIO_DELAY 250
     25 #define MDIO_READ_DELAY 350
     26 
     27 /*  Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit 
     28  *   IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. 
     29  *   */ 
     30 #define MII_ADDR_C45 (1<<30)
     31 
     32 #define MDIO_READ 2
     33 #define MDIO_WRITE 1
     34 
     35 #define MDIO_C45 (1<<15)
     36 #define MDIO_C45_ADDR (MDIO_C45 | 0)
     37 #define MDIO_C45_READ (MDIO_C45 | 3)
     38 #define MDIO_C45_WRITE (MDIO_C45 | 1)
     39 
     40 #define MDIO_SETUP_TIME 10
     41 #define MDIO_HOLD_TIME 10
     42 
     43 
     44 //#define READ_REG 0x37
     45 //#define WRITE_REG 0x38
     46 
     47 
     48 #define MDIO_C45_TEST 0
     49 
     50 
     51 typedef struct gpio_ctrl_blk{
     52     int pin;
     53     int value;
     54 }gpio_cblk_t;
     55 
     56 typedef struct phy_reg_blk{
     57     unsigned int phy_address;
     58     unsigned int reg_address;
     59     unsigned int reg_value;
     60 }phy_reg_cblk_t;
     61 
     62 
     63 #define MDIO_DEV_ID 't'
     64 #define READ_REG             _IOWR (MDIO_DEV_ID,0x37,phy_reg_cblk_t)
     65 #define WRITE_REG            _IOWR (MDIO_DEV_ID,0x38,phy_reg_cblk_t)
     66 static void MDC_OUT(void);
     67 static void MDIO_OUT(void);
     68 static void MDIO_IN(void);
     69 static void MDC_H(void);
     70 static void MDC_L(void);
     71 static int GET_MDIO(void);
     72 static void SET_MDIO(int val);
     73 
     74 
     75 /* 设置MDC为输出引脚,在MDC输出时钟之前设置 */
     76 static void MDC_OUT(void)
     77 {
     78     gpio_cblk_t gpio_dev;
     79     gpio_dev.pin = MDC;
     80     at91_set_gpio_output(gpio_dev.pin,1); 
     81 }
     82 
     83 /* 设置MDIO的gpio引脚为输出引脚 */
     84 static void MDIO_OUT(void)
     85 {
     86     gpio_cblk_t gpio_dev;
     87     gpio_dev.pin = MDIO;
     88     at91_set_gpio_output(gpio_dev.pin,1); 
     89 }
     90 
     91 /* 设置MDIO的gpio引脚为输入引脚 */
     92 static void MDIO_IN(void)
     93 {
     94     gpio_cblk_t gpio_dev;
     95     gpio_dev.pin = MDIO;
     96     at91_set_gpio_input(gpio_dev.pin,1); 
     97 }
     98 
     99 /* MDC输出高电平,在MDC设置为输出后调用 */
    100 static void MDC_H(void)
    101 {
    102     gpio_cblk_t gpio_dev;
    103 
    104     gpio_dev.pin = MDC;
    105     gpio_dev.value = 1;
    106     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
    107 }
    108 
    109 /* MDC输出低电平,在MDC设置为输出后调用 */
    110 static void MDC_L(void)
    111 {
    112     gpio_cblk_t gpio_dev;
    113 
    114     gpio_dev.pin = MDC;
    115     gpio_dev.value = 0;
    116     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
    117 }
    118 
    119 /* 获得MDIO的数据,只获得一个bit */
    120 static int GET_MDIO(void)
    121 {
    122     gpio_cblk_t gpio_dev;
    123 
    124     gpio_dev.pin = MDIO;
    125     gpio_dev.value = at91_get_gpio_value(gpio_dev.pin);
    126 
    127     return gpio_dev.value;
    128 }
    129 
    130 /* 设置MDIO的数据,一个bit */
    131 static void SET_MDIO(int val)
    132 {
    133     gpio_cblk_t gpio_dev;
    134 
    135     gpio_dev.pin = MDIO;
    136     gpio_dev.value = val;
    137     at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
    138 }
    139 
    140 
    141 /* MDIO发送一个bit的数据,MDIO必须已经被配置为输出 */
    142 static void mdio_bb_send_bit(int val)
    143 {
    144     MDC_OUT();    
    145     SET_MDIO(val);
    146     ndelay(MDIO_DELAY);
    147     MDC_L();
    148     ndelay(MDIO_DELAY);
    149     MDC_H();
    150 }
    151 
    152 /*  MDIO 获取一个bit的数据,MDIO必须已经被配置为输入. */   
    153 static int mdio_bb_get_bit(void)
    154 {
    155     int value;
    156 
    157     MDC_OUT();    
    158     ndelay(MDIO_DELAY);
    159     MDC_L();
    160     ndelay(MDIO_READ_DELAY);
    161 //    ndelay(MDIO_DELAY);
    162     MDC_H();
    163     
    164     value = GET_MDIO();
    165     
    166     return value;
    167 }
    168 
    169  /*  
    170   *  MDIO发送一个数据,MDIO 必须被配置为输出模式. 
    171   *  value:要发送的数据
    172   *  bits:数据的位数
    173   *  
    174   *  */  
    175 static void mdio_bb_send_num(unsigned int value ,int bits)
    176 {
    177     int i;
    178     MDIO_OUT();
    179     
    180     for(i = bits - 1; i >= 0; i--)
    181         mdio_bb_send_bit((value >> i) & 1);
    182 }
    183 
    184  /*  
    185   *  MDIO获取一个数据,MDIO 必须被配置为输入模式. 
    186   *  bits:获取数据的位数
    187   *  
    188   *  */  
    189 static int mdio_bb_get_num(int bits)
    190 {
    191     int i;
    192     int ret = 0;
    193     for(i = bits - 1; i >= 0; i--)
    194     {
    195         ret <<= 1;
    196         ret |= mdio_bb_get_bit(); 
    197     }
    198 
    199     return ret;
    200 }
    201 
    202 
    203 
    204 /*  Utility to send the preamble, address, and
    205 *   register (common to read and write). 
    206 */
    207 static void mdio_bb_cmd(int op,int phy,int reg)
    208 {
    209     int i = 0 ;
    210     MDIO_OUT();  //设置MDIO引脚为输出引脚
    211 
    212     /*发送32bit的1,这个帧前缀域不是必须的,某些物理层芯片的MDIO操作就没有这个域*/
    213     for(i = 0; i < 32; i++)
    214         mdio_bb_send_bit(1);
    215 
    216 
    217     /* 发送开始位(01),和读操作码(10),写操作码(01)
    218      * Clause 45 操作,开始位是(00),(11)为读,(10)为写
    219     */
    220 
    221 #if MDIO_C45_TEST
    222     mdio_bb_send_bit(0);
    223     if(op & MDIO_C45)
    224         mdio_bb_send_bit(0);
    225     else
    226         mdio_bb_send_bit(1);
    227 
    228 
    229 #else
    230     mdio_bb_send_bit(0);
    231     mdio_bb_send_bit(1);
    232     
    233 #endif
    234     mdio_bb_send_bit((op >> 1) & 1);
    235     mdio_bb_send_bit((op >> 0) & 1);
    236 
    237     mdio_bb_send_num(phy,5);
    238     mdio_bb_send_num(reg,5);
    239 
    240 }
    241 
    242 static int mdio_bb_cmd_addr(int phy,int addr)
    243 {
    244     unsigned int dev_addr = (addr >> 16) & 0x1F;
    245     unsigned int reg = addr & 0xFFFF;
    246 
    247     mdio_bb_cmd(MDIO_C45_ADDR,phy,dev_addr);
    248 
    249     /*  send the turnaround (10) */  
    250     mdio_bb_send_bit(1);
    251     mdio_bb_send_bit(0);
    252 
    253     mdio_bb_send_num(reg,16);
    254     
    255     MDIO_IN();
    256     mdio_bb_get_bit();
    257 
    258     return dev_addr;
    259 }
    260 
    261 void mdio_set_turnaround(void)
    262 {
    263     int i = 0;
    264 
    265     MDIO_IN();
    266     MDC_OUT();
    267     for(i=0;i<2;i++)
    268     {
    269         ndelay(MDIO_DELAY);
    270         MDC_L();
    271         ndelay(MDIO_DELAY);
    272         MDC_H();
    273     }
    274 }
    275 
    276 static unsigned int mdio_bb_read(int phy,int reg)
    277 {
    278     unsigned int ret,i;
    279 
    280 #if MDIO_C45_TEST
    281     /* 寄存器是否满足有C45标志 */
    282     if(reg & MII_ADDR_C45)
    283     {
    284         reg = mdio_bb_cmd_addr(phy,reg);
    285         mdio_bb_cmd(MDIO_C45_READ,phy,reg);
    286     }
    287     else
    288         mdio_bb_cmd(MDIO_READ,phy,reg);
    289 #else
    290         mdio_bb_cmd(MDIO_READ,phy,reg);
    291 #endif
    292     MDIO_IN();
    293     //mdio_set_turnaround();
    294     /*  check the turnaround bit: the PHY should be driving it to zero */ 
    295     if(mdio_bb_get_bit() != 0)
    296     {
    297         /* PHY didn't driver TA low -- flush any bits it may be trying to send*/
    298         for(i = 0; i < 32; i++)
    299             mdio_bb_get_bit();
    300         return 0xFFFF;
    301     }
    302 
    303     ret = mdio_bb_get_num(16);
    304     mdio_bb_get_bit();
    305     
    306     return ret;
    307 }
    308 
    309 
    310 
    311 static int mdio_bb_write(unsigned int phy,unsigned int reg,unsigned int val)
    312 {
    313 #if MDIO_C45_TEST
    314     if(reg & MII_ADDR_C45)
    315     {
    316         reg = mdio_bb_cmd_addr(phy,reg);
    317         mdio_bb_cmd(MDIO_C45_WRITE,phy,reg);
    318     }
    319     else
    320         mdio_bb_cmd(MDIO_WRITE,phy,reg);
    321 #else
    322         mdio_bb_cmd(MDIO_WRITE,phy,reg);
    323 #endif
    324 
    325 
    326 #if 1
    327     /*  send the turnaround (10) */  
    328     mdio_bb_send_bit(1);
    329     mdio_bb_send_bit(0);
    330 #else
    331     mdio_set_turnaround();
    332 #endif
    333     mdio_bb_send_num(val,16);
    334     
    335     MDIO_IN();
    336     //mdio_bb_get_bit();
    337 
    338     return 0;
    339 }
    340 
    341 
    342 static int mdio_ctrl_drv_open(struct inode *inode, struct file *file )
    343 {
    344     return 0;
    345 }
    346 
    347 static int mdio_ctrl_drv_release(struct inode *inode, struct file *file )
    348 {
    349     return 0;
    350 }
    351 
    352 static long mdio_ctrl_drv_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    353 {
    354     phy_reg_cblk_t phy_reg;
    355     int ret = 0;
    356     
    357      void __user *argp = (void __user *)arg;
    358      if( argp==NULL )
    359      {
    360          return -EFAULT; 
    361      }
    362 
    363     if (copy_from_user(&phy_reg, argp, sizeof(phy_reg_cblk_t))) {
    364                 return -EFAULT;
    365             }
    366     
    367     switch (cmd) {
    368     case READ_REG:
    369             phy_reg.reg_value = mdio_bb_read(phy_reg.phy_address,phy_reg.reg_address);
    370             if(copy_to_user(argp,&phy_reg,sizeof(phy_reg_cblk_t)))
    371             {
    372                 return -EFAULT;
    373             }
    374             break;
    375     case WRITE_REG:
    376             ret = mdio_bb_write(phy_reg.phy_address,phy_reg.reg_address,phy_reg.reg_value);
    377     default:
    378         return -EINVAL;
    379 
    380     }
    381     
    382     return 0;
    383 }
    384 
    385 static struct file_operations mdio_ctl_drv_fileops = {
    386     .owner = THIS_MODULE,
    387     .open = mdio_ctrl_drv_open,
    388     .unlocked_ioctl = mdio_ctrl_drv_unlocked_ioctl,
    389     .release = mdio_ctrl_drv_release
    390 };
    391 
    392 static struct miscdevice mdio_dev = {
    393     MISC_DYNAMIC_MINOR,
    394     "mdio_dev",
    395     &mdio_ctl_drv_fileops,
    396 };
    397 
    398 
    399 int mdio_ctrl_drv_module_init(void)
    400 {
    401     int ret = 0;
    402 
    403     ret = misc_register(&mdio_dev);
    404     if(ret != 0)
    405     {
    406         ret = -EFAULT;
    407         return ret;
    408     }
    409     printk("mdio_drv_init ok
    ");
    410     return 0;
    411 }
    412 
    413 
    414 void mdio_ctrl_drv_module_exit(void)
    415 {
    416     misc_deregister(&mdio_dev);
    417     printk("mdio_drv_exit ok
    ");
    418 }
    419 
    420 
    421 
    422 module_init(mdio_ctrl_drv_module_init);
    423 module_exit(mdio_ctrl_drv_module_exit);
    424 MODULE_LICENSE("GPL");
    View Code
  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/hjj801006/p/4864638.html
Copyright © 2011-2022 走看看