• 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
  • 相关阅读:
    [导入]C#中将字符串转成 Base64 编码
    [导入]GridView中实现并列排名的例子
    VB.net编程中可能用到的边边角角(二) —— 取Mac地址、取某String的MD5值、多线程、RAR压缩、ADOX生成数据库、加载工程内的Form、一个滚动条控制两个DataGridView
    (转)Setup Factory 打包工具部分功能代码解析
    (转)SQL 优化原则
    VB.net编程中可能用到的边边角角(一) —— 反射添加Form、向Excel中写值
    自写的简单屏蔽特定字符的TextBox和数字TextBox
    spring import resource 文件后bean找不到问题解决
    mysql插入记录后获取插入数据的id值
    cookie+memcached实现单点登陆
  • 原文地址:https://www.cnblogs.com/hjj801006/p/4864638.html
Copyright © 2020-2023  润新知