Linux设备驱动之I2C架构分析--暂存

Linux I2C设备驱动编写(三)-实例分析AM3359 TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格支持标准模式(100K bits/s)和快速模式(400K bits/s)多路接收、发送模式支持7bit、10bit设备地址模式32字节FIFO缓冲区可编程时钟发生器双DMA通道,一条中断线三个I2C模块实例I2C0\I2C1\I2C2时钟信号能够达到最高48MHz,来自PRCM 不 阅读详情
 
Linux设备驱动之I2C架构分析
一:前言
I2c是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.另外,I2C是一种多主机控制总线.它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须由主机发起才可以.而I2C是基于multi master机制.一同总线上可允许多个master.关于I2C协议的知识,这里不再赘述.可自行下载spec阅读即可.
二:I2C架构概述
在linux中,I2C驱动架构如下所示:

如上图所示,每一条I2C对应一个adapter.在kernel中,每一个adapter提供了一个描述的结构(struct i2c_adapter),也定义了adapter支持的操作(struct i2c_adapter).再通过i2c core层将i2c设备与i2c adapter关联起来.
这个图只是提供了一个大概的框架.在下面的代码分析中,从下至上的来分析这个框架图.以下的代码分析是基于linux 2.6.26.分析的代码基本位于: linux-2.6.26.3/drivers/i2c/位置.
三:adapter注册
在kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号.这个总线号的PCI中的总线号不同.它和硬件无关,只是软件上便于区分而已.
对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败.
分别来看一下这两个函数的代码:
int i2c_add_adapter(struct i2c_adapter *adapter)
{
    int id, res = 0;
retry:
    if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
        return -ENOMEM;
    mutex_lock(&core_lock);
    /* "above" here means "above or equal to", sigh */
    res = idr_get_new_above(&i2c_adapter_idr, adapter,
                __i2c_first_dynamic_bus_num, &id);
    mutex_unlock(&core_lock);
    if (res < 0) {
        if (res == -EAGAIN)
            goto retry;
        return res;
    }
    adapter->nr = id;
    return i2c_register_adapter(adapter);
}
在这里涉及到一个idr结构.idr结构本来是为了配合page cache中的radix tree而设计的.在这里我们只需要知道,它是一种高效的搜索树,且这个树预先存放了一些内存.避免在内存不够的时候出现问题.所在,在往idr中插入结构的时候,首先要调用idr_pre_get()为它预留足够的空闲内存,然后再调用idr_get_new_above()将结构插入idr中,该函数以参数的形式返回一个id.以后凭这个id就可以在idr中找到相对应的结构了.对这个数据结构操作不太理解的可以查阅本站<< linux文件系统之文件的读写>>中有关radix tree的分析.
注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)的参数的含义,它是将adapter结构插入到i2c_adapter_idr中,存放位置的id必须要大于或者等于__i2c_first_dynamic_bus_num,
然后将对应的id号存放在adapter->nr中.调用i2c_register_adapter(adapter)对这个adapter进行进一步注册.
看一下另外一人注册函数: i2c_add_numbered_adapter( ),如下所示:
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
    int id;
    int status;
    if (adap->nr & ~MAX_ID_MASK)
        return -EINVAL;
retry:
    if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
        return -ENOMEM;
    mutex_lock(&core_lock);
    /* "above" here means "above or equal to", sigh;
     * we need the "equal to" result to force the result
     */
    status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
    if (status == 0 && id != adap->nr) {
        status = -EBUSY;
        idr_remove(&i2c_adapter_idr, id);
    }
    mutex_unlock(&core_lock);
    if (status == -EAGAIN)
        goto retry;
    if (status == 0)
        status = i2c_register_adapter(adap);
    return status;
}
对比一下就知道差别了,在这里它已经指定好了adapter->nr了.如果分配的id不和指定的相等,便返回错误.
过一步跟踪i2c_register_adapter().代码如下:
static int i2c_register_adapter(struct i2c_adapter *adap)
{
    int res = 0, dummy;
    mutex_init(&adap->bus_lock);
    mutex_init(&adap->clist_lock);
    INIT_LIST_HEAD(&adap->clients);
    mutex_lock(&core_lock);
    /* Add the adapter to the driver core.
     * If the parent pointer is not set up,
     * we add this adapter to the host bus.
     */
    if (adap->dev.parent == NULL) {
        adap->dev.parent = &platform_bus;
        pr_debug("I2C adapter driver [%s] forgot to specify "
             "physical device ", adap->name);
    }
    sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
    adap->dev.release = &i2c_adapter_dev_release;
    adap->dev.class = &i2c_adapter_class;
    res = device_register(&adap->dev);
    if (res)
        goto out_list;
    dev_dbg(&adap->dev, "adapter [%s] registered ", adap->name);
    /* create pre-declared device nodes for new-style drivers */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);
    /* let legacy drivers scan this bus for matching devices */
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 i2c_do_add_adapter);
out_unlock:
    mutex_unlock(&core_lock);
    return res;
out_list:
    idr_remove(&i2c_adapter_idr, adap->nr);
    goto out_unlock;
}
首先对adapter和adapter中内嵌的struct device结构进行必须的初始化.之后将adapter内嵌的struct device注册.
在这里注意一下adapter->dev的初始化.它的类别为i2c_adapter_class,如果没有父结点,则将其父结点设为platform_bus.adapter->dev的名字为i2c + 总线号.
测试一下:
[eric@mochow i2c]$ cd /sys/class/i2c-adapter/
[eric@mochow i2c-adapter]$ ls
i2c-0
可以看到,在我的PC上,有一个I2C adapter,看下详细信息:
[eric@mochow i2c-adapter]$ tree
.
`-- i2c-0
    |-- device -> ../../../devices/pci0000:00/0000:00:1f.3/i2c-0
    |-- name
    |-- subsystem -> ../../../class/i2c-adapter
    `-- uevent
3 directories, 2 files
可以看到,该adapter是一个PCI设备.
继续往下看:
之后,在注释中看到,有两种类型的driver,一种是new-style drivers,另外一种是legacy drivers
New-style drivers是在2.6近版的kernel加入的.它们最主要的区别是在adapter和i2c driver的匹配上.
3.1: new-style 形式的adapter注册
对于第一种,也就是new-style drivers,将相关代码再次列出如下:
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);
如果adap->nr 小于__i2c_first_dynamic_bus_num的话,就会进入到i2c_scan_static_board_info().
结合我们之前分析的adapter的两种注册分式: i2c_add_adapter()所分得的总线号肯会不会小于__i2c_first_dynamic_bus_num.只有i2c_add_numbered_adapter()才有可能满足:
(adap->nr < __i2c_first_dynamic_bus_num)
而且必须要调用i2c_register_board_info()将板子上的I2C设备信息预先注册时才会更改__i2c_first_dynamic_bus_num的值.在x86上只没有使用i2c_register_board_info()的.因此,x86平台上的分析可以忽略掉new-style driver的方式.不过,还是详细分析这种情况下.
首先看一下i2c_register_board_info(),如下:
int __init
i2c_register_board_info(int busnum,
    struct i2c_board_info const *info, unsigned len)
{
    int status;
    mutex_lock(&__i2c_board_lock);
    /* dynamic bus numbers will be assigned after the last static one */
    if (busnum >= __i2c_first_dynamic_bus_num)
        __i2c_first_dynamic_bus_num = busnum + 1;
    for (status = 0; len; len--, info++) {
        struct i2c_devinfo  *devinfo;
        devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
        if (!devinfo) {
            pr_debug("i2c-core: can't register boardinfo! ");
            status = -ENOMEM;
            break;
        }
        devinfo->busnum = busnum;
        devinfo->board_info = *info;
        list_add_tail(&devinfo->list, &__i2c_board_list);
    }
    mutex_unlock(&__i2c_board_lock);
    return status;
}
这个函数比较简单, struct i2c_board_info用来表示I2C设备的一些情况,比如所在的总线.名称,地址,中断号等.最后,这些信息会被存放到__i2c_board_list链表.
跟踪i2c_scan_static_board_info():代码如下:
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo  *devinfo;
    mutex_lock(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,
                        &devinfo->board_info))
            printk(KERN_ERR "i2c-core: can't create i2c%d-%04x ",
                i2c_adapter_id(adapter),
                devinfo->board_info.addr);
    }
    mutex_unlock(&__i2c_board_lock);
}
该函数遍历挂在__i2c_board_list链表上面的i2c设备的信息,也就是我们在启动的时候指出的i2c设备的信息.
如果指定设备是位于adapter所在的I2C总线上,那么,就调用i2c_new_device().代码如下:
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
    struct i2c_client   *client;
    int         status;
    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
        return NULL;
    client->adapter = adap;
    client->dev.platform_data = info->platform_data;
    device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);
    client->flags = info->flags & ~I2C_CLIENT_WAKE;
    client->addr = info->addr;
    client->irq = info->irq;
    strlcpy(client->name, info->type, sizeof(client->name));
    /* a new style driver may be bound to this device when we
     * return from this function, or any later moment (e.g. maybe
     * hotplugging will load the driver module).  and the device
     * refcount model is the standard driver model one.
     */
    status = i2c_attach_client(client);
    if (status < 0) {
        kfree(client);
        client = NULL;
    }
    return client;
}
我们又遇到了一个新的结构:struct i2c_client,不要被这个结构吓倒了,其实它就是一个嵌入struct device的I2C设备的封装.它和我们之前遇到的struct usb_device结构的作用是一样的.
首先,在clinet里保存该设备的相关消息.特别的, client->adapter指向了它所在的adapter.
特别的,clinet->name为info->name.也是指定好了的.
一切初始化完成之后,便会调用i2c_attach_client( ).看这个函数的字面意思,是将clinet关联起来.到底怎么样关联呢?继续往下看:
int i2c_attach_client(struct i2c_client *client)
{
    struct i2c_adapter *adapter = client->adapter;
    int res = 0;
    //初始化client内嵌的dev结构
    //父结点为所在的adapter,所在bus为i2c_bus_type
    client->dev.parent = &client->adapter->dev;
    client->dev.bus = &i2c_bus_type;
    //如果client已经指定了driver,将driver和内嵌的dev关联起来
    if (client->driver)
        client->dev.driver = &client->driver->driver;
    //指定了driver, 但不是newstyle的
    if (client->driver && !is_newstyle_driver(client->driver)) {
        client->dev.release = i2c_client_release;
        client->dev.uevent_suppress = 1;
    } else
        client->dev.release = i2c_client_dev_release;
    //clinet->dev的名称
    snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
        "%d-%04x", i2c_adapter_id(adapter), client->addr);
    //将内嵌的dev注册
    res = device_register(&client->dev);
    if (res)
        goto out_err;
    //将clinet链到adapter->clients中
    mutex_lock(&adapter->clist_lock);
    list_add_tail(&client->list, &adapter->clients);
    mutex_unlock(&adapter->clist_lock);
    dev_dbg(&adapter->dev, "client [%s] registered with bus id %s ",
        client->name, client->dev.bus_id);
    //如果adapter->cleinet_reqister存在,就调用它
    if (adapter->client_register)  {
        if (adapter->client_register(client)) {
            dev_dbg(&adapter->dev, "client_register "
                "failed for client [%s] at 0x%02x ",
                client->name, client->addr);
        }
    }
    return 0;
out_err:
    dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
        "(%d) ", client->name, client->addr, res);
    return res;
}
参考上面添加的注释,应该很容易理解这段代码了,就不加详细分析了.这个函数的名字不是i2c_attach_client()么?怎么没看到它的关系过程呢?
这是因为:在代码中设置了client->dev所在的bus为i2c_bus_type .以为只需要有bus为i2c_bus_type的driver注册,就会产生probe了.这个过程呆后面分析i2c driver的时候再来详细分析.
3.2: legacy形式的adapter注册
Legacy形式的adapter注册代码片段如下:
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 i2c_do_add_adapter);
这段代码遍历挂在i2c_bus_type上的驱动,然后对每一个驱动和adapter调用i2c_do_add_adapter().
代码如下:
static int i2c_do_add_adapter(struct device_driver *d, void *data)
{
    struct i2c_driver *driver = to_i2c_driver(d);
    struct i2c_adapter *adap = data;
    if (driver->attach_adapter) {
        /* We ignore the return code; if it fails, too bad */
        driver->attach_adapter(adap);
    }
    return 0;
}
该函数很简单,就是调用driver的attach_adapter()接口.
到此为止,adapter的注册已经分析完了.
四:i2c driver注册
在分析i2c driver的时候,有必要先分析一下i2c架构的初始化
代码如下:
static int __init i2c_init(void)
{
    int retval;
    retval = bus_register(&i2c_bus_type);
    if (retval)
        return retval;
    retval = class_register(&i2c_adapter_class);
    if (retval)
        goto bus_err;
    retval = i2c_add_driver(&dummy_driver);
    if (retval)
        goto class_err;
    return 0;
class_err:
    class_unregister(&i2c_adapter_class);
bus_err:
    bus_unregister(&i2c_bus_type);
    return retval;
}
subsys_initcall(i2c_init);
很明显,i2c_init()会在系统初始化的时候被调用.
在i2c_init中,先注册了i2c_bus_type的bus,i2c_adapter_class的class.然后再调用i2c_add_driver()注册了一个i2c driver.
I2c_bus_type结构如下:
static struct bus_type i2c_bus_type = {
    .name       = "i2c",
    .dev_attrs  = i2c_dev_attrs,
    .match      = i2c_device_match,
    .uevent     = i2c_device_uevent,
    .probe      = i2c_device_probe,
    .remove     = i2c_device_remove,
    .shutdown   = i2c_device_shutdown,
    .suspend    = i2c_device_suspend,
    .resume     = i2c_device_resume,
};
这个结构先放在这里吧,以后还会用到里面的信息的.
从上面的初始化函数里也看到了,注册i2c driver的接口为i2c_add_driver().代码如下:
static inline int i2c_add_driver(struct i2c_driver *driver)
{
    return i2c_register_driver(THIS_MODULE, driver);
}
继续跟踪:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
    int res;
    /* new style driver methods can't mix with legacy ones */
    //如果是一个newstyle的driver.但又定义了attach_adapter/detach_adapter.非法
    if (is_newstyle_driver(driver)) {
        if (driver->attach_adapter || driver->detach_adapter
                || driver->detach_client) {
            printk(KERN_WARNING
                    "i2c-core: driver [%s] is confused ",
                    driver->driver.name);
            return -EINVAL;
        }
    }
    /* add the driver to the list of i2c drivers in the driver core */
    //关联到i2c_bus_types
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;
    /* for new style drivers, when registration returns the driver core
     * will have called probe() for all matching-but-unbound devices.
     */
     //注册内嵌的driver
    res = driver_register(&driver->driver);
    if (res)
        return res;
    mutex_lock(&core_lock);
    pr_debug("i2c-core: driver [%s] registered ", driver->driver.name);
    /* legacy drivers scan i2c busses directly */
    //遍历所有的adapter,对其都调用driver->attach_adapter
    if (driver->attach_adapter) {
        struct i2c_adapter *adapter;
        down(&i2c_adapter_class.sem);
        list_for_each_entry(adapter, &i2c_adapter_class.devices,
                    dev.node) {
            driver->attach_adapter(adapter);
        }
        up(&i2c_adapter_class.sem);
    }
    mutex_unlock(&core_lock);
    return 0;
}
这里也有两种形式的区分,对于第一种,只需要将内嵌的driver注册就可以了,对于legacy的情况,对每一个adapter都调用driver->attach_adapter().
现在,我们可以将adapter和i2c driver关联起来考虑一下了:
1:如果是news style形式的,在注册adapter的时候,将它上面的i2c 设备转换成了struct client.struct client->dev->bus又指定了和i2c driver同一个bus.因为,它们可以发生probe.
2:如果是legacy形式,就直接找到对应的对象,调用driver->attach_adapter().
实战封神!YOLOv7 轻量化部署全攻略:ONNX格式转换+TensorRT极致加速(速度直接提升3-5倍,精度无损) 部署核心链路,这是YOLO系列部署的最优解,速度提升3~5倍,精度无损;ONNX是桥梁:解决模型兼容性问题,简化后能去掉冗余节点,是TensorRT加速的前提;TensorRT是核心:NVIDIA显卡的极致加速引擎,FP16量化是速度与精度的最优平衡,无需手动配置,一键开启;轻量化终极组合YOLOv7-tiny + 416尺寸 + TensorRT FP16,速度提升5~8倍,满足所有实时检测场景;避坑核心:转换参数必加,推理尺寸必须一致,engine文件显卡专属。 阅读详情

相关推荐

RedVQA:轻量级无参考视频质量评估算法原理与工程实践

视频质量评估是计算机视觉领域的关键技术,旨在通过算法自动量化视频的观看体验。其核心原理在于模拟人眼视觉系统,从像素数据中提取并融合空域和时域特征,以预测主观质量分数。这项技术的价值在于,它能自动化处理海量视频内容的质量监控,为流媒体服务、移动设备影像优化等场景提供关键指标。无参考视频质量评估作为该领域的前沿方向,无需原始无损视频作为参考,更贴合实际应用。本文以RedVQA项目为例,深入剖析了如何利用轻量化的深度网络架构,如MobileNetV3,结合高效的时空特征融合模块,在保证评估精度的同时,大幅降低计算

weixin_28698129的博客 576

Linux设备驱动之I2C架构分析(一)

Linux设备驱动之I2C架构分析一:前言I2c是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.另外,I2C是一种多主机控制总线.它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须由主机发起才可以.而I2C是基于multi master机制.一同总线上可允许多个ma...

weixin_34112030的博客 139

14.4kW大功率母线变换器设计:LLC+矩阵变压器+GaN实战解析

在数据中心供电架构中,隔离母线变换器将高压直流母线转换为48V低压母线,是大功率供电链路的核心环节。随着功率密度与效率要求不断攀升,传统移相全桥与普通LLC方案已难以满足300A级输出需求。基于LLC/CLLC谐振拓扑,结合矩阵变压器与GaN功率器件,成为新一代高性能母线变换器的主流技术路线。矩阵变压器将大功率磁性元件拆分为多个小单元,配合原边串联副边并联结构,有效降低绕组损耗并提升功率密度;GaN器件则通过高频软开关进一步压减开关损耗。本文以一台14.4kW样机为例,完整梳理从拓扑选型、谐振参数计算、同步

weixin_28273593的博客 345

linux iic设备读写,Linux 应用技术--I2C设备读写

#include //#define CHIP_ADDR 0x20#define I2C_DEV "/dev/i2c-0"//i2c_dev为i2c adapter创建的别名//读操作先发Slaveaddr_W+Regaddr_H+Regaddr_L 3个字节来告诉设备操作器件及两个byte参数//然后发送Slaveaddr_R读数据static int iic_read(int fd, char...

weixin_33462167的博客 1122

【技能---ubuntu20.04更换国内镜像源】

安装好ubuntu20.04后,在下载软件等安装包的时候,速度特别的慢,为此就想着更换一下镜像源,以此来增加下载的速度!!!下面是换源的具体流程!!!提示:以下是本篇文章正文内容,下面案例可供参考以上到这里就更换完软件源了,如有不足之处,请大家斧正!!!

fyc300的博客 1万+

PyQt5简介和安装

在initUI方法中,设置了窗口的标题和大小,并创建了一个按钮。PyQt5是一个功能强大的Python界面开发框架,可以轻松创建跨平台的图形用户界面应用程序。本文介绍了PyQt5的简介和安装方法,并提供了一个简单的示例应用程序来演示PyQt5的基本用法。PyQt5是一个功能强大的Python界面开发框架,它提供了丰富的工具和组件,用于创建跨平台的图形用户界面(GUI)应用程序。信号是控件发出的事件,槽是与之关联的处理函数。接下来,我们将编写一个简单的PyQt5应用程序,以演示PyQt5的基本用法。

XdKwargs的博客 225

《Linux开发中关于I2C和寄存器的读写方式探讨|寻找C站宝藏》

在做Android系统开发时,特别是现在智能显示和物联网,经常客户会要求搭配各种外接模块。Android系统与外接模块的通讯方式主要有I2C通讯、USB通讯、串口UART通讯、蓝牙通讯等。我们现在只探讨下I2C通讯。 I2C通讯又分两种,一种是通过读写寄存器;一种是不带寄存器直接读写I2C。读写寄存器的方式也存在差异,此文以Mstar平台来说明。 1、读写I2C下寄存器数据 现以读写光感模块ISL29023为列说明。 首先需要定义I2C设备的地址:ISL29023_IIC_ADD 然后获取I2C设

神仙猪的专栏 1637

零基础学simulink仿真建模--基于Simulink进行近端策略优化(PPO)路径规划的仿真建模

特点高效性与稳定性:通过引入剪裁机制,在更新策略时限制步长,从而提高了训练过程的稳定性和效率。适用于多种动作空间:可以处理连续和离散的动作空间问题。无需模型:不需要预先知道环境的确切模型,适合复杂或未知环境。挑战收敛速度与稳定性:确保算法能够在合理的时间内找到近似最优解,并保持训练过程的稳定性。探索与利用平衡:在探索新路径和利用已知信息之间取得平衡。计算资源:对于大规模状态空间和动作空间,计算资源需求较高。首先明确要模拟的任务内容。目标(例如到达指定地点、避开障碍物等)。

amy_mhd的博客 252

linux 下i2c读写命令,Linux下读写芯片的I2C寄存器

I2C 知识

li5830的博客 1580

企业数字化建设之——品牌零售全渠道运营中台解决方案

OMS审单 --> 订单进入OMS待发货列表区域 --> 备货(线下)-->拣货((线下 )-->质检(线下)--> 包装(线下)--> 快递员取货(线下)(物品 + 客户收货地址清单 )--> 快递员发货(2.2.5 正常退货,客户发起 --> 客服助理审核 --> 评审组 --> ( 货物运输 ) -->质检 ->仓库收货入 正常仓库 -->财务退款,记账。OMS审单 --> 订单进入物流公司系统(如:*丰),--> 快递员发货 --> 物流状态同步OMS --> OMS同步物流状态到销售平台。

java_zhong1990的专栏 612

RK3568平台(网络篇)添加网络交换芯片RTL8306M

该交换芯片支持I2C、SPI、mdio通信,但是看ast1520的uboot代码采用的是mdio去通信phy芯片的,所以暂时也先采用mdio的方式,需要配置相应的引脚才可以配置成mdio通信模式,具体的配置硬件工程师解决。RTL8306M芯片上可能没有提供MDC/MDIO接口,可以通过GPIO(General Purpose Input/Output)来模拟,GPIO可实现串行输入输出,且一般CPU上会提供很多GPIO接口供用户自定义使用。

weixin_49303682的博客 3938

msm7227平台Linux I2C驱动分析(2.6.29)

目录 1. 摘要 2. 简介 3. I2C架构 4. I2C总线初始化 5. I2C适配器驱动 6. I2C设备驱动 7. 用户空间驱动支持 8. 数据传输框架 9. References   1. 摘要 主要介绍Msm7227平台上I2C驱动原理,多数部分是29内核标准架构。 2. 简介 I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL。

Bloom and Grow 1110

Android Binder的两三事--基于Android14源码

Android14-Framework-Binder

保持专注,保持热爱 1142

Linux I2C 设备驱动分析(接上上一节)

include <linux/module.h> // 模块基础接口(如module_init/exit)#include <linux/i2c.h> // I2C总线核心接口(i2c_client、i2c_driver等)#include <linux/interrupt.h> // 中断处理接口(request_irq、irqreturn_t等)#include <linux/gpio.h> // GPIO操作接口(gpio_to_irq等)

shanstellar的博客 528

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【转】Linux I2C设备驱动编写(三)-实例分析AM3359

原文网址:http://www.cnblogs.com/biglucky/p/4059586.html TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收、发送模式 支持7bit、10bit设备地址模式 32字节FIFO缓冲区 可编程时钟...

weixin_34168880的博客 174

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

i2c驱动

i2c_dev 驱动注册 static int __init i2c_dev_init(void){ register_chrdev_region } i2cdev_attach_adapter i2c-dev.c的核心 static const struct file_operations i2cdev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = i2cdev_read, .write = i2cdev_w

weixin_43490398的博客 318

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

嵌入式Linux八股文(面试高频考点)

platform和i2c和spi的区别在代码编写方面基本没有区别。

dbabeb的博客 1279

[没事乱分析] Freescal mma8452 probe函数乱分析

static int mma8452_probe(struct i2c_client *client, const struct i2c_device_id *id){ int err = 0;//储存错误信息 int tempvalue = 0;//储存8452配置寄存器的读值 struct mma8452_data *data;//自定义8452数据结构体 if(!i2c_c

FcabilitY的专栏 1542
上一篇: 关于apk安装时,Packagepaser报错: <provider> does not incude authorities attribute
下一篇: __weak 说明
勤奋专注
博客等级 码龄19年 80粉丝 69原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值