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

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

 #include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/completion.h>
#include <asm/system.h>
#include <linux/param.h>
#include<linux/gpio.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/slab.h>
#include<asm/uaccess.h>
#include<linux/delay.h>
#include<linux/miscdevice.h> /* bb:bit-bang,通过gpio引脚,用软件模拟通信*/ #define MDIO 117 /* MDIO correspond PD21 */
#define MDC 116 /* MDC correspond PD20 */
#define MDIO_DELAY 250
#define MDIO_READ_DELAY 350 /* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
* IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
* */
#define MII_ADDR_C45 (1<<30) #define MDIO_READ 2
#define MDIO_WRITE 1 #define MDIO_C45 (1<<15)
#define MDIO_C45_ADDR (MDIO_C45 | 0)
#define MDIO_C45_READ (MDIO_C45 | 3)
#define MDIO_C45_WRITE (MDIO_C45 | 1) #define MDIO_SETUP_TIME 10
#define MDIO_HOLD_TIME 10 //#define READ_REG 0x37
//#define WRITE_REG 0x38 #define MDIO_C45_TEST 0 typedef struct gpio_ctrl_blk{
int pin;
int value;
}gpio_cblk_t; typedef struct phy_reg_blk{
unsigned int phy_address;
unsigned int reg_address;
unsigned int reg_value;
}phy_reg_cblk_t; #define MDIO_DEV_ID 't'
#define READ_REG _IOWR (MDIO_DEV_ID,0x37,phy_reg_cblk_t)
#define WRITE_REG _IOWR (MDIO_DEV_ID,0x38,phy_reg_cblk_t)
static void MDC_OUT(void);
static void MDIO_OUT(void);
static void MDIO_IN(void);
static void MDC_H(void);
static void MDC_L(void);
static int GET_MDIO(void);
static void SET_MDIO(int val); /* 设置MDC为输出引脚,在MDC输出时钟之前设置 */
static void MDC_OUT(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = MDC;
at91_set_gpio_output(gpio_dev.pin,);
} /* 设置MDIO的gpio引脚为输出引脚 */
static void MDIO_OUT(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = MDIO;
at91_set_gpio_output(gpio_dev.pin,);
} /* 设置MDIO的gpio引脚为输入引脚 */
static void MDIO_IN(void)
{
gpio_cblk_t gpio_dev;
gpio_dev.pin = MDIO;
at91_set_gpio_input(gpio_dev.pin,);
} /* MDC输出高电平,在MDC设置为输出后调用 */
static void MDC_H(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = MDC;
gpio_dev.value = ;
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* MDC输出低电平,在MDC设置为输出后调用 */
static void MDC_L(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = MDC;
gpio_dev.value = ;
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* 获得MDIO的数据,只获得一个bit */
static int GET_MDIO(void)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = MDIO;
gpio_dev.value = at91_get_gpio_value(gpio_dev.pin); return gpio_dev.value;
} /* 设置MDIO的数据,一个bit */
static void SET_MDIO(int val)
{
gpio_cblk_t gpio_dev; gpio_dev.pin = MDIO;
gpio_dev.value = val;
at91_set_gpio_value(gpio_dev.pin,gpio_dev.value);
} /* MDIO发送一个bit的数据,MDIO必须已经被配置为输出 */
static void mdio_bb_send_bit(int val)
{
MDC_OUT();
SET_MDIO(val);
ndelay(MDIO_DELAY);
MDC_L();
ndelay(MDIO_DELAY);
MDC_H();
} /* MDIO 获取一个bit的数据,MDIO必须已经被配置为输入. */
static int mdio_bb_get_bit(void)
{
int value; MDC_OUT();
ndelay(MDIO_DELAY);
MDC_L();
ndelay(MDIO_READ_DELAY);
// ndelay(MDIO_DELAY);
MDC_H(); value = GET_MDIO(); return value;
} /*
* MDIO发送一个数据,MDIO 必须被配置为输出模式.
* value:要发送的数据
* bits:数据的位数
*
* */
static void mdio_bb_send_num(unsigned int value ,int bits)
{
int i;
MDIO_OUT(); for(i = bits - ; i >= ; i--)
mdio_bb_send_bit((value >> i) & );
} /*
* MDIO获取一个数据,MDIO 必须被配置为输入模式.
* bits:获取数据的位数
*
* */
static int mdio_bb_get_num(int bits)
{
int i;
int ret = ;
for(i = bits - ; i >= ; i--)
{
ret <<= ;
ret |= mdio_bb_get_bit();
} return ret;
} /* Utility to send the preamble, address, and
* register (common to read and write).
*/
static void mdio_bb_cmd(int op,int phy,int reg)
{
int i = ;
MDIO_OUT(); //设置MDIO引脚为输出引脚 /*发送32bit的1,这个帧前缀域不是必须的,某些物理层芯片的MDIO操作就没有这个域*/
for(i = ; i < ; i++)
mdio_bb_send_bit(); /* 发送开始位(01),和读操作码(10),写操作码(01)
* Clause 45 操作,开始位是(00),(11)为读,(10)为写
*/ #if MDIO_C45_TEST
mdio_bb_send_bit();
if(op & MDIO_C45)
mdio_bb_send_bit();
else
mdio_bb_send_bit(); #else
mdio_bb_send_bit();
mdio_bb_send_bit(); #endif
mdio_bb_send_bit((op >> ) & );
mdio_bb_send_bit((op >> ) & ); mdio_bb_send_num(phy,);
mdio_bb_send_num(reg,); } static int mdio_bb_cmd_addr(int phy,int addr)
{
unsigned int dev_addr = (addr >> ) & 0x1F;
unsigned int reg = addr & 0xFFFF; mdio_bb_cmd(MDIO_C45_ADDR,phy,dev_addr); /* send the turnaround (10) */
mdio_bb_send_bit();
mdio_bb_send_bit(); mdio_bb_send_num(reg,); MDIO_IN();
mdio_bb_get_bit(); return dev_addr;
} void mdio_set_turnaround(void)
{
int i = ; MDIO_IN();
MDC_OUT();
for(i=;i<;i++)
{
ndelay(MDIO_DELAY);
MDC_L();
ndelay(MDIO_DELAY);
MDC_H();
}
} static unsigned int mdio_bb_read(int phy,int reg)
{
unsigned int ret,i; #if MDIO_C45_TEST
/* 寄存器是否满足有C45标志 */
if(reg & MII_ADDR_C45)
{
reg = mdio_bb_cmd_addr(phy,reg);
mdio_bb_cmd(MDIO_C45_READ,phy,reg);
}
else
mdio_bb_cmd(MDIO_READ,phy,reg);
#else
mdio_bb_cmd(MDIO_READ,phy,reg);
#endif
MDIO_IN();
//mdio_set_turnaround();
/* check the turnaround bit: the PHY should be driving it to zero */
if(mdio_bb_get_bit() != )
{
/* PHY didn't driver TA low -- flush any bits it may be trying to send*/
for(i = ; i < ; i++)
mdio_bb_get_bit();
return 0xFFFF;
} ret = mdio_bb_get_num();
mdio_bb_get_bit(); return ret;
} static int mdio_bb_write(unsigned int phy,unsigned int reg,unsigned int val)
{
#if MDIO_C45_TEST
if(reg & MII_ADDR_C45)
{
reg = mdio_bb_cmd_addr(phy,reg);
mdio_bb_cmd(MDIO_C45_WRITE,phy,reg);
}
else
mdio_bb_cmd(MDIO_WRITE,phy,reg);
#else
mdio_bb_cmd(MDIO_WRITE,phy,reg);
#endif #if 1
/* send the turnaround (10) */
mdio_bb_send_bit();
mdio_bb_send_bit();
#else
mdio_set_turnaround();
#endif
mdio_bb_send_num(val,); MDIO_IN();
//mdio_bb_get_bit(); return ;
} static int mdio_ctrl_drv_open(struct inode *inode, struct file *file )
{
return ;
} static int mdio_ctrl_drv_release(struct inode *inode, struct file *file )
{
return ;
} static long mdio_ctrl_drv_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
phy_reg_cblk_t phy_reg;
int ret = ; void __user *argp = (void __user *)arg;
if( argp==NULL )
{
return -EFAULT;
} if (copy_from_user(&phy_reg, argp, sizeof(phy_reg_cblk_t))) {
return -EFAULT;
} switch (cmd) {
case READ_REG:
phy_reg.reg_value = mdio_bb_read(phy_reg.phy_address,phy_reg.reg_address);
if(copy_to_user(argp,&phy_reg,sizeof(phy_reg_cblk_t)))
{
return -EFAULT;
}
break;
case WRITE_REG:
ret = mdio_bb_write(phy_reg.phy_address,phy_reg.reg_address,phy_reg.reg_value);
default:
return -EINVAL; } return ;
} static struct file_operations mdio_ctl_drv_fileops = {
.owner = THIS_MODULE,
.open = mdio_ctrl_drv_open,
.unlocked_ioctl = mdio_ctrl_drv_unlocked_ioctl,
.release = mdio_ctrl_drv_release
}; static struct miscdevice mdio_dev = {
MISC_DYNAMIC_MINOR,
"mdio_dev",
&mdio_ctl_drv_fileops,
}; int mdio_ctrl_drv_module_init(void)
{
int ret = ; ret = misc_register(&mdio_dev);
if(ret != )
{
ret = -EFAULT;
return ret;
}
printk("mdio_drv_init ok\n");
return ;
} void mdio_ctrl_drv_module_exit(void)
{
misc_deregister(&mdio_dev);
printk("mdio_drv_exit ok\n");
} module_init(mdio_ctrl_drv_module_init);
module_exit(mdio_ctrl_drv_module_exit);
MODULE_LICENSE("GPL");

gpio模拟mdc/mdio通信的更多相关文章

  1. S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动

    目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...

  2. gpio模拟i2c驱动

    前段时间做项目,需要gpio模拟i2c通信,最后参考了一些资料,然后编写了一个程序.现在发出来,以免以后忘记,也为一些需要的朋友提供参考.不喜勿喷哈. /* 说明:该程序是基于atmel公司的sama ...

  3. GPIO模拟IIC接口信号质量分析

    信号质量有问题的波形001: 信号质量有问题的波形002: 从上图可以看出,GPIO口模拟的I2C接口,电平都存在半高的情况. 因为I2C的接口是通过GPIO模拟实现的,该时钟信号线SCL内部默认为下 ...

  4. GPIO模拟串口注意是事项

    GPIO模拟串口需要注意的事项如下:(程序见我的博客第一篇) 1.由于串口是异步通信,则串口发送必须满足宽度要求. (1)假设串口的波特率是9600bps(1s传输9600个bit),则传输1bit需 ...

  5. 通用GPIO模拟串口,提供源代码,本人经过测试OK(第一版)

    --------------------------serial.h------------------------------------------ #ifndef _SERIAL_H_ #def ...

  6. STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数

    1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...

  7. GPIO模拟SPI

    上次用gpio模拟i2c理解i2c协议.相同的,我用gpio模拟spi来理解spi协议. 我用的是4线spi,四线各自是片选.时钟.命令/数据.数据. 数据在时钟上升沿传递,数据表示的是数据还是命令由 ...

  8. linux SPI驱动——gpio模拟spi驱动(三)

    一:首先在我的平台注册platform_device,保证能让spi-gpio.c能执行到probe函数. 1: struct spi_gpio_platform_data { 2: unsigned ...

  9. 【转载】GPIO模拟i2c通信

    I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主 ...

随机推荐

  1. AndroidStudio查找硬编码的String字符串

    在Menu的“Analyze”中,选择“Run Inspection By Name”,然后输入“Hardcoded strings”,执行后,可以找到所有没有加入strings.xml的字符串. 按 ...

  2. ElasticSearch(一)概念介绍及环境搭建

    一.什么是ElasticSearch: Elasticsearch (ES)是一个基于Lucene构建的开源.分布式.RESTful 接口全文搜索引擎.Elasticsearch 还是一个分布式文档数 ...

  3. EF批量插入太慢?那是你的姿势不对

    大概所有的程序员应该都接触过批量插入的场景,我也相信任何的程序员都能写出可正常运行的批量插入的代码.但怎样实现一个高效.快速插入的批量插入功能呢? 由于每个人的工作履历,工作年限的不同,在实现这样的一 ...

  4. 日志分析-利用grep,awk等文本处理工具完成(2019-4-9)

    0x00 基础日志分析命令 1. tail - 监控末尾日志的变化 $tail -n 10 error2019.log #显示最后10行日志内容 $tail -n +5 nginx2019.log # ...

  5. python的pyc文件

    编译型语言在程序执行之前,先会通过编译器对程序执行一个编译的过程,把程序转变成机器语言.运行时就不需要翻译,而直接执行就可以了.最典型的例子就是C语言. 解释型语言就没有这个编译的过程,而是在程序运行 ...

  6. Java Web(5)-Servlet详解(上)

    一.Servlet 1. 什么是Servlet Servlet 是 JavaEE 规范之一,规范就是接口 Servlet 就 JavaWeb 三大组件之一,三大组件分别是:Servlet 程序.Fil ...

  7. Java 添加、删除、替换、格式化Word中的文本(基于Spire.Cloud.SDK for Java)

    Spire.Cloud.SDK for Java提供了TextRangesApi接口可通过addTextRange()添加文本.deleteTextRange()删除文本.updateTextRang ...

  8. PHP addChild() 函数

    实例 给 body 元素和 footer 元素添加一个子元素: <?php$note=<<<XML<note>高佣联盟 www.cgewang.com<to& ...

  9. 程序员面试:C/C++求职者必备 20 道面试题,一道试题一份信心!

    面试真是痛并快乐的一件事,痛在被虐的体无完肤,快乐在可以短时间内积累很多问题,加速学习. 在我们准备面试的时候,遇到的面试题有难有易,不能因为容易,我们就轻视,更不能因为难,我们就放弃.我们面对高薪就 ...

  10. 使用IDEA生成jar包的步骤(IDEA打jar包)

    第一步: 1.把module目录下的MATA-INF文件夹删除,如果没有MATA-INF文件夹则不用删除 2.Ctrl + Alt + Shift + S 打开 Project Structure 窗 ...