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 接口使用代码相关推荐

  1. 解析java实现模拟USB接口的功能

    解析java实现模拟USB接口的功能 1 题目 模拟USB接口的功能 我们在使用计算机的时候经常会用到USB接口,鼠标.键盘等都是带USB接口的设备,我们只需要将鼠标.键盘插入到计算机的USB接口中就 ...

  2. 用GPIO模拟SPI接口读取传感器数据

    本文基于平头哥开发板RVB2601,简要介绍了用GPIO模拟SPI时序逻辑,实现SPI协议,按照特定温度传感器的时序,读取其数据,及示例程序 一.概述 SPI(Serial Peripheral In ...

  3. Linux I2C子系统分析之(一) ----- 用GPIO模拟I2C总线

    在drivers/i2c/busses下包含各种I2C总线驱动,如S3C2440的I2C总线驱动i2c-s3c2410.c,使用GPIO模拟I2C总线的驱动i2c-gpio.c,这里只分析i2c-gp ...

  4. Hook Com接口函数

    标 题:  [原创]COM接口函数通用Hook方法 作 者: zhangluduo 时 间: 2014-12-08,22:34:20 链 接: http://bbs.pediy.com/showthr ...

  5. 【嵌入式】Libmodbus源码分析(二)-常用接口函数分析

    00. 目录 文章目录 00. 目录 01. modbus常用接口函数概述 02. modbus辅助接口函数 03. modbus功能接口函数 04. modbus数据处理 05. 附录 01. mo ...

  6. linux内核的外部接口函数,linux内核中GPIO的使用(二)--标准接口函数

    在linux内核中,有一些基本模块可以使用标准的接口函数来操作,比如GPIO.interrupt.clock,所谓的标准接口函数是指一些与硬件平台无关的.linux下做驱动通用的函数, 常用的有: g ...

  7. 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )

    文章目录 一.Linux 内核 动态分配内存 系统接口函数 二.统计输出 vmalloc 分配的内存 一.Linux 内核 动态分配内存 系统接口函数 Linux 内核 " 动态分配内存 & ...

  8. 线程及其相关接口函数(Linux)

    目录 一.线程 1.线程相关接口函数 (1)创建线程 pthread_create() (2)结束线程 pthread_exit() (3)等待进程 pthread_join() 2.线程间通信 (1 ...

  9. Linux内核编程接口函数

    Linux内核编程接口函数 转载请注明出处: http://blog.csdn.net/drivelinux/article/details/8656280 字符设备相关函数 1.alloc_chrd ...

  10. linux信号子系统,Linux时间子系统之(三):用户空间接口函数

    Linux时间子系统之(三):用户空间接口函数 作者:linuxer 发布于:2014-12-24 15:48 分类:时间子系统 一.前言 从应用程序的角度看,内核需要提供的和时间相关的服务有三种: ...

最新文章

  1. JavaScript 工作原理(一):引擎,运行时,调用堆栈
  2. 用div来创建田字布局
  3. android studio wcf,将图像从android studio上传到Wcf Service
  4. PIC单片机精通_A/D转换异步串口通讯实例与详解
  5. 工业机器人打磨抛光编程员工资_让我们一起来谈谈,工业机器人行业的真实工资是多少?...
  6. FreeBSD 配置
  7. Java SE 疑难点记录
  8. 德江多措施推进大数据应用“智慧德江”建设
  9. Synchronized与ReentrantLock的区别
  10. 用户登陆问题,session.invalidate销毁session
  11. 单片机初始化WIFI模块
  12. python 显著性检验_Python SciPy 统计显著性检验(Statistical Significance Tests)
  13. 中文翻译英文-免费批量中文英文翻译互转软件
  14. SSL证书申请流程,中文域名如何申请证书?
  15. NLP算法-词性标注
  16. 2021年7月程序员工资统计,平均15302元
  17. opencv cvhog详解
  18. python怎么隐藏输入法_打开和关闭输入法
  19. AcWing 1017 怪盗基德的滑翔翼
  20. Git如何上传文件到gitee?

热门文章

  1. (转)开源GIS总结(一)——总结
  2. 小程序父子组件间传值(微信/支付宝/钉钉)
  3. 【20届考研终章--落幕】北京邮电大学软件学院--学硕
  4. matlab将数据集分成训练集和测试集,如何将数据分成训练集和测试集?
  5. Java NIO 模型代码示例
  6. project哪个版本好用
  7. 软件设计师--判定覆盖,判定条件覆盖,条件组合覆盖--一个栗子
  8. wincc远程服务器配置,如何配置WINCC作为OPC服务器?
  9. Sklearn聚类算法之meanshift
  10. 龙芯2F一体机硬盘修复