linux访问mdio接口函数,MII 接口解析(三)GPIO 模拟 MDIO 接口使用代码
GPIO 模拟 MDIO 接口使用代码
如果要通过GPIO来模拟MDIO通信,那么我们就是通过模拟其帧格式的时序来通信,
前面介绍过一遍其帧格式了,MDIO上数据帧的格式如下:
mdio frame
内核中提供了一个mdio-bitbang.c,里面实现了一套软件实现的MDIO/MDC接口时序可供参考。
数据结构
struct mdiobb_ops {
struct module *owner;
/* Set the Management Data Clock high if level is one,
* low if level is zero.
*/
void (*set_mdc)(struct mdiobb_ctrl *ctrl, int level);
/* Configure the Management Data I/O pin as an input if
* "output" is zero, or an output if "output" is one.
*/
void (*set_mdio_dir)(struct mdiobb_ctrl *ctrl, int output);
/* Set the Management Data I/O pin high if value is one,
* low if "value" is zero. This may only be called
* when the MDIO pin is configured as an output.
*/
void (*set_mdio_data)(struct mdiobb_ctrl *ctrl, int value);
/* Retrieve the state Management Data I/O pin. */
int (*get_mdio_data)(struct mdiobb_ctrl *ctrl);
};
struct mdiobb_ctrl {
const struct mdiobb_ops *ops;
};
set_mdc,发送MDC 信号的函数,由具体使用情况来决定实际的mdc 信号是如何发送
set_mdio_dir,设置MDIO方向的函数,由具体使用情况来决定实际的mdc 信号是如何发送
set_mdio_data,发送MDIO数据到MMD,由具体使用情况来决定实际的mdc 信号是如何发送
get_mdio_data,从MMD接收MDIO数据,由具体使用情况来决定实际的mdc 信号是如何发送
使用方法
通过调用 alloc_mdio_bitbang 来获得一个mii_bus, 并且注册read/wirte 方法为 mdiobb_read/mdiobb_write,并且将mdiobb_ctrl 作为mii bus的私有成员来操作器后续的ops 函数
struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
{
struct mii_bus *bus;
bus = mdiobus_alloc();
if (!bus)
return NULL;
__module_get(ctrl->ops->owner);
bus->read = mdiobb_read;
bus->write = mdiobb_write;
bus->priv = ctrl;
return bus;
}
以wirte 为例,bitbang中帮我们封装好了对应的时序,我们需要做的就是定义好前面注册的 ops mdc mdio操作
static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
struct mdiobb_ctrl *ctrl = bus->priv;
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
} else
mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
/* send the turnaround (10) */
mdiobb_send_bit(ctrl, 1);
mdiobb_send_bit(ctrl, 0);
mdiobb_send_num(ctrl, val, 16);
ctrl->ops->set_mdio_dir(ctrl, 0);
mdiobb_get_bit(ctrl);
return 0;
}
内核中也有一个GPIOI-MDIO的例子,可以参考其来移植到自己的驱动中
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct mdio_gpio_info {
struct mdiobb_ctrl ctrl;
struct gpio_desc *mdc, *mdio, *mdo;
};
static int mdio_gpio_get_data(struct device *dev,
struct mdio_gpio_info *bitbang)
{
bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC,
GPIOD_OUT_LOW);
if (IS_ERR(bitbang->mdc))
return PTR_ERR(bitbang->mdc);
bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO,
GPIOD_IN);
if (IS_ERR(bitbang->mdio))
return PTR_ERR(bitbang->mdio);
bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO,
GPIOD_OUT_LOW);
return PTR_ERR_OR_ZERO(bitbang->mdo);
}
static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
if (bitbang->mdo) {
/* Separate output pin. Always set its value to high
* when changing direction. If direction is input,
* assume the pin serves as pull-up. If direction is
* output, the default value is high.
*/
gpiod_set_value_cansleep(bitbang->mdo, 1);
return;
}
if (dir)
gpiod_direction_output(bitbang->mdio, 1);
else
gpiod_direction_input(bitbang->mdio);
}
static int mdio_get(struct mdiobb_ctrl *ctrl)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
return gpiod_get_value_cansleep(bitbang->mdio);
}
static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
if (bitbang->mdo)
gpiod_set_value_cansleep(bitbang->mdo, what);
else
gpiod_set_value_cansleep(bitbang->mdio, what);
}
static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
gpiod_set_value_cansleep(bitbang->mdc, what);
}
static const struct mdiobb_ops mdio_gpio_ops = {
.owner = THIS_MODULE,
.set_mdc = mdc_set,
.set_mdio_dir = mdio_dir,
.set_mdio_data = mdio_set,
.get_mdio_data = mdio_get,
};
static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
struct mdio_gpio_info *bitbang,
int bus_id)
{
struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev);
struct mii_bus *new_bus;
bitbang->ctrl.ops = &mdio_gpio_ops;
new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
if (!new_bus)
return NULL;
new_bus->name = "GPIO Bitbanged MDIO";
new_bus->parent = dev;
if (bus_id != -1)
snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
else
strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE);
if (pdata) {
new_bus->phy_mask = pdata->phy_mask;
new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
}
dev_set_drvdata(dev, new_bus);
return new_bus;
}
static void mdio_gpio_bus_deinit(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
free_mdio_bitbang(bus);
}
static void mdio_gpio_bus_destroy(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
mdiobus_unregister(bus);
mdio_gpio_bus_deinit(dev);
}
static int mdio_gpio_probe(struct platform_device *pdev)
{
struct mdio_gpio_info *bitbang;
struct mii_bus *new_bus;
int ret, bus_id;
bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL);
if (!bitbang)
return -ENOMEM;
ret = mdio_gpio_get_data(&pdev->dev, bitbang);
if (ret)
return ret;
if (pdev->dev.of_node) {
bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio");
if (bus_id < 0) {
dev_warn(&pdev->dev, "failed to get alias id\n");
bus_id = 0;
}
} else {
bus_id = pdev->id;
}
new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id);
if (!new_bus)
return -ENODEV;
ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
if (ret)
mdio_gpio_bus_deinit(&pdev->dev);
return ret;
}
static int mdio_gpio_remove(struct platform_device *pdev)
{
mdio_gpio_bus_destroy(&pdev->dev);
return 0;
}
static const struct of_device_id mdio_gpio_of_match[] = {
{ .compatible = "virtual,mdio-gpio", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
static struct platform_driver mdio_gpio_driver = {
.probe = mdio_gpio_probe,
.remove = mdio_gpio_remove,
.driver = {
.name = "mdio-gpio",
.of_match_table = mdio_gpio_of_match,
},
};
module_platform_driver(mdio_gpio_driver);
MODULE_ALIAS("platform:mdio-gpio");
MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
DTS 配置
参考 Documentation/devicetree/bindings/net/mdio-gpio.txt 配置即可
linux访问mdio接口函数,MII 接口解析(三)GPIO 模拟 MDIO 接口使用代码相关推荐
- 解析java实现模拟USB接口的功能
解析java实现模拟USB接口的功能 1 题目 模拟USB接口的功能 我们在使用计算机的时候经常会用到USB接口,鼠标.键盘等都是带USB接口的设备,我们只需要将鼠标.键盘插入到计算机的USB接口中就 ...
- 用GPIO模拟SPI接口读取传感器数据
本文基于平头哥开发板RVB2601,简要介绍了用GPIO模拟SPI时序逻辑,实现SPI协议,按照特定温度传感器的时序,读取其数据,及示例程序 一.概述 SPI(Serial Peripheral In ...
- Linux I2C子系统分析之(一) ----- 用GPIO模拟I2C总线
在drivers/i2c/busses下包含各种I2C总线驱动,如S3C2440的I2C总线驱动i2c-s3c2410.c,使用GPIO模拟I2C总线的驱动i2c-gpio.c,这里只分析i2c-gp ...
- Hook Com接口函数
标 题: [原创]COM接口函数通用Hook方法 作 者: zhangluduo 时 间: 2014-12-08,22:34:20 链 接: http://bbs.pediy.com/showthr ...
- 【嵌入式】Libmodbus源码分析(二)-常用接口函数分析
00. 目录 文章目录 00. 目录 01. modbus常用接口函数概述 02. modbus辅助接口函数 03. modbus功能接口函数 04. modbus数据处理 05. 附录 01. mo ...
- linux内核的外部接口函数,linux内核中GPIO的使用(二)--标准接口函数
在linux内核中,有一些基本模块可以使用标准的接口函数来操作,比如GPIO.interrupt.clock,所谓的标准接口函数是指一些与硬件平台无关的.linux下做驱动通用的函数, 常用的有: g ...
- 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )
文章目录 一.Linux 内核 动态分配内存 系统接口函数 二.统计输出 vmalloc 分配的内存 一.Linux 内核 动态分配内存 系统接口函数 Linux 内核 " 动态分配内存 & ...
- 线程及其相关接口函数(Linux)
目录 一.线程 1.线程相关接口函数 (1)创建线程 pthread_create() (2)结束线程 pthread_exit() (3)等待进程 pthread_join() 2.线程间通信 (1 ...
- Linux内核编程接口函数
Linux内核编程接口函数 转载请注明出处: http://blog.csdn.net/drivelinux/article/details/8656280 字符设备相关函数 1.alloc_chrd ...
- linux信号子系统,Linux时间子系统之(三):用户空间接口函数
Linux时间子系统之(三):用户空间接口函数 作者:linuxer 发布于:2014-12-24 15:48 分类:时间子系统 一.前言 从应用程序的角度看,内核需要提供的和时间相关的服务有三种: ...
最新文章
- JavaScript 工作原理(一):引擎,运行时,调用堆栈
- 用div来创建田字布局
- android studio wcf,将图像从android studio上传到Wcf Service
- PIC单片机精通_A/D转换异步串口通讯实例与详解
- 工业机器人打磨抛光编程员工资_让我们一起来谈谈,工业机器人行业的真实工资是多少?...
- FreeBSD 配置
- Java SE 疑难点记录
- 德江多措施推进大数据应用“智慧德江”建设
- Synchronized与ReentrantLock的区别
- 用户登陆问题,session.invalidate销毁session
- 单片机初始化WIFI模块
- python 显著性检验_Python SciPy 统计显著性检验(Statistical Significance Tests)
- 中文翻译英文-免费批量中文英文翻译互转软件
- SSL证书申请流程,中文域名如何申请证书?
- NLP算法-词性标注
- 2021年7月程序员工资统计,平均15302元
- opencv cvhog详解
- python怎么隐藏输入法_打开和关闭输入法
- AcWing 1017 怪盗基德的滑翔翼
- Git如何上传文件到gitee?