本文主要是学习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. Centos 7下编译安装Nginx

    一.下载源代码 百度云网盘下载地址:https://pan.baidu.com/s/19MQODvofRNnLV9hdAT-R6w 提取码:zi0u 二.安装依赖及插件 yum -y install ...

  2. Skill 脚本演示 ycLayerExcel.il

    https://www.cnblogs.com/yeungchie/ ycLayerExcel.il 用于 Tape-out 流程,获取当前用到的所有 lpp 等信息,并按照自定格式输出为 Excel ...

  3. luogu P2525 Uim的情人节礼物 其之壱

    LINK:Uim的情人节礼物·其之壱 壱 古代通壹 常在日文中出现. 完全可以使用STL -->prev_permutation来解决. 不过我简单了解了一下康托展开. 这是一个一个排列对应一个 ...

  4. Hadoop学习之TextInputFormat分片逻辑探究

    期望 顺着上一篇文章<Hadoop学习之第一个MapReduce程序>中遗留的分片疑惑,探究TextInputFormat的分片逻辑. 第一步 上Apache官网下载实验所使用的Hadoo ...

  5. Idea快捷生成serialVersionUID

    Java对象实现了Serializable接口,是需要创建serialVersionUID,避免此对象在序列化.反序列化时出现问题.但idea默认没有生成serialVersionUID的设置,需要手 ...

  6. 苹果挖矿恶意程序处理(OSX/CoinMiner.X)

    背景 近期通过流量告警发现多起外连矿池的告警,均外连至43.249.204.231 威胁情报信息如下: 系统表象 1.通过ps -ef|grep osascript发现在/library/Launch ...

  7. 树状图展示终端目录内容-tree

    以树状图列出目录的内容,让你一目了然 执行 tree 指令,它会列出指定目录下的所有文件,包括子目录里的文件. 安装 我们通过包管理工具可以方便的安装它 mac - brew install tree ...

  8. 关于saltstack的job问题

    问题背景:搭建一个多节点后端集群,使用saltstack作为底层管理,使用Python封装saltstack接口成逻辑层.通过逻辑层的调用实现对整个集群的运维管理. 问题:随着项目中模块的增多,发现s ...

  9. Java线程生命周期与状态切换

    前提 最近有点懒散,没什么比较有深度的产出.刚好想重新研读一下JUC线程池的源码实现,在此之前先深入了解一下Java中的线程实现,包括线程的生命周期.状态切换以及线程的上下文切换等等.编写本文的时候, ...

  10. Python实现图片滑动式验证识别

    1 abstract 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类 ...