gpio模拟mdc/mdio通信
本文主要是学习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通信的更多相关文章
- S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动
目录:一. 说明 二. 驱动程序说明及问题 三. 案例一 四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...
- gpio模拟i2c驱动
前段时间做项目,需要gpio模拟i2c通信,最后参考了一些资料,然后编写了一个程序.现在发出来,以免以后忘记,也为一些需要的朋友提供参考.不喜勿喷哈. /* 说明:该程序是基于atmel公司的sama ...
- GPIO模拟IIC接口信号质量分析
信号质量有问题的波形001: 信号质量有问题的波形002: 从上图可以看出,GPIO口模拟的I2C接口,电平都存在半高的情况. 因为I2C的接口是通过GPIO模拟实现的,该时钟信号线SCL内部默认为下 ...
- GPIO模拟串口注意是事项
GPIO模拟串口需要注意的事项如下:(程序见我的博客第一篇) 1.由于串口是异步通信,则串口发送必须满足宽度要求. (1)假设串口的波特率是9600bps(1s传输9600个bit),则传输1bit需 ...
- 通用GPIO模拟串口,提供源代码,本人经过测试OK(第一版)
--------------------------serial.h------------------------------------------ #ifndef _SERIAL_H_ #def ...
- STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数
1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...
- GPIO模拟SPI
上次用gpio模拟i2c理解i2c协议.相同的,我用gpio模拟spi来理解spi协议. 我用的是4线spi,四线各自是片选.时钟.命令/数据.数据. 数据在时钟上升沿传递,数据表示的是数据还是命令由 ...
- linux SPI驱动——gpio模拟spi驱动(三)
一:首先在我的平台注册platform_device,保证能让spi-gpio.c能执行到probe函数. 1: struct spi_gpio_platform_data { 2: unsigned ...
- 【转载】GPIO模拟i2c通信
I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主 ...
随机推荐
- Python灰帽子:黑客与逆向工程师的Python编程之道|百度网盘免费下载|新手黑客入门
百度网盘免费下载:Python灰帽子:黑客与逆向工程师的Python编程之道 提取码:tgpg 目录 · · · · · · 第1章 搭建开发环境 11.1 操作系统要求 11.2 获取和安装Pyt ...
- java基础(七)--键盘输入
一.示例 package cnblogs; import java.util.Scanner; public class TestBase07IO { public static void main( ...
- 使用AB对Nginx压测和并发预估
简介 ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基于URL的. # 1.ab每次只能测试一个URL,适合做重复压力测试 # 2.参数很多,可以支持添加c ...
- 使用brew services管理服务
简介 官网: https://github.com/Homebrew/homebrew-services macOS使用launchctl命令加载开机自动运行的服务,brew service可以简化l ...
- Python异常及异常处理
Python异常及异常处理: 当程序运行时,发生的错误称为异常 例: 0 不能作为除数:ZeroDivisionError 变量未定义:NameError 不同类型进行相加:TypeError 异常处 ...
- pandas_数据拆分与合并
import pandas as pd import numpy as np # 读取全部数据,使用默认索引 data = pd.read_excel(r'C:\Users\lenovo\Deskto ...
- 8-Pandas之如何查找存在缺失值的行(any与all详解)
若有一份数据,简略如下: 国家 啤酒消耗量 烈酒消耗量 红酒消耗量 总酒精消耗量 所在大洲 0 Afghanistan 0.0 0.0 0.0 0.0 AS 1 Albania 89.0 132. ...
- PHP ucfirst() 函数
实例 把 "hello" 的首字符转换为大写: <?phpecho ucfirst("hello world!");?> 运行实例 » 定义和用法 ...
- [草稿] Linux 各种 打包 / 解包 命令
https://www.cnblogs.com/yeungchie/ 有不少错误 .tar格式 解包: tar -xvf FileName.tar 打包: tar -cvf FileName.tar ...
- 6.18 省选模拟赛 字符串 LCT SAM
LINK:字符串 看起来很难做 考虑一种暴力 建立SAM后每次查询暴力扫儿子. 期望得分10分.实际得分10分. 另外一种发现每次扫儿子过于暴力 可以每次儿子向上做贡献 每次都暴力向上跳. 期望得分1 ...