I2C 地址转换器

作者:Luca Ceresoli <luca@lucaceresoli.net> 作者:Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

描述

I2C 地址转换器 (ATR) 是一种具有 I2C 从设备父端口(“上游”)和 N 个 I2C 主设备子端口(“下游”)的设备,它将事务从上游转发到适当的下游端口,并修改了从设备地址。父总线上使用的地址称为“别名”,并且(可能)与子总线的物理从设备地址不同。地址转换由硬件完成。

ATR 看起来类似于 i2c-mux,但
  • 父总线和子总线上的地址可能不同

  • 通常不需要选择子端口;父总线上使用的别名隐含了这一点

ATR 功能可以由具有许多其他功能的芯片提供。内核 i2c-atr 提供了一个帮助程序,用于在驱动程序中实现 ATR。

ATR 在每个子总线上创建一个新的 I2C “子”适配器。在子总线上添加设备最终会调用驱动程序代码来选择可用的别名。维护适当的可用别名池并为每个新设备选择一个别名由驱动程序实现者负责。ATR 维护当前分配的别名表,并使用它来修改所有指向子总线上设备的 I2C 事务。

下面是一个典型的例子。

拓扑

                    Slave X @ 0x10
            .-----.   |
.-----.     |     |---+---- B
| CPU |--A--| ATR |
`-----'     |     |---+---- C
            `-----'   |
                    Slave Y @ 0x10

别名表

A、B 和 C 是三个物理 I2C 总线,彼此在电气上独立。ATR 接收在总线 A 上发起的事务,并根据事务中的设备地址和别名表,将其传播到总线 B 或总线 C 或不传播。

别名表

客户端

别名

X(总线 B,0x10)

0x20

Y(总线 C,0x10)

0x30

事务

  • 从设备 X 驱动程序请求一个事务(在适配器 B 上),从设备地址为 0x10

  • ATR 驱动程序发现从设备 X 在总线 B 上,别名为 0x20,使用地址 0x20 重写消息,转发到适配器 A

  • 总线 A 上的物理 I2C 事务,从设备地址为 0x20

  • ATR 芯片检测到地址为 0x20 的事务,在表中找到它,在总线 B 上传播事务,地址转换为 0x10,保持总线 A 上的时钟拉伸,等待回复

  • 从设备 X 芯片(在总线 B 上)检测到其自身物理地址 0x10 的事务,并正常回复

  • ATR 芯片停止时钟拉伸,并在总线 A 上转发回复,地址转换回 0x20

  • ATR 驱动程序接收到回复,使用地址 0x10 重写消息,就像最初一样

  • 从设备 X 驱动程序获得 msgs[],其中包含回复和地址 0x10

用法

  1. 在驱动程序中(通常在探测函数中),通过调用 i2c_atr_new() 并传递附加/分离回调来添加 ATR

  2. 当调用附加回调时,选择一个适当的别名,在芯片中配置它,并在 alias_id 参数中返回所选的别名

  3. 当调用分离回调时,从芯片中取消配置别名,并将别名放回池中以供以后使用

I2C ATR 函数和数据结构

struct i2c_atr_ops

从 ATR 到设备驱动程序的回调。

定义:

struct i2c_atr_ops {
    int (*attach_client)(struct i2c_atr *atr, u32 chan_id, const struct i2c_client *client, u16 alias);
    void (*detach_client)(struct i2c_atr *atr, u32 chan_id, const struct i2c_client *client);
};

成员

attach_client

通知驱动程序在子总线上连接了一个新设备,并为其分配了别名。驱动程序必须配置硬件以使用该别名。

detach_client

通知驱动程序设备已断开连接。驱动程序必须配置硬件以停止使用该别名。

描述

所有这些函数在成功时返回 0,否则返回负错误代码。

struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, const struct i2c_atr_ops *ops, int max_adapters)

分配和初始化 I2C ATR 帮助程序。

参数

struct i2c_adapter *parent

父(上游)适配器

struct device *dev

充当 ATR 的设备

const struct i2c_atr_ops *ops

驱动程序特定的回调

int max_adapters

子适配器的最大数量

描述

新的 ATR 帮助程序已连接到父适配器,但没有子适配器。调用 i2c_atr_add_adapter() 以添加一些。

调用 i2c_atr_delete() 以删除。

返回

指向新 ATR 帮助程序对象的指针,或 ERR_PTR

void i2c_atr_delete(struct i2c_atr *atr)

删除 I2C ATR 帮助程序。

参数

struct i2c_atr *atr

要删除的 I2C ATR 帮助程序。

描述

前提条件:使用 i2c_atr_add_adapter() 添加的所有适配器必须通过调用 i2c_atr_del_adapter() 删除。

int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, struct device *adapter_parent, struct fwnode_handle *bus_handle)

创建子(“下游”)I2C 总线。

参数

struct i2c_atr *atr

I2C ATR

u32 chan_id

新适配器的索引 (0 .. max_adapters-1)。此值会传递给 struct i2c_atr_ops 中的回调。

struct device *adapter_parent

用作新 i2c 适配器的父设备的设备,或 NULL 以使用 i2c-atr 设备作为父设备。

struct fwnode_handle *bus_handle

指向适配器 i2c 外围设备的 fwnode 句柄,或 NULL。

描述

调用此函数后,将出现一条新的 i2c 总线。在下游总线上添加和删除设备将导致调用 i2c_atr_ops->attach_clienti2c_atr_ops->detach_client 回调,以便驱动程序为设备分配别名。

适配器的 fwnode 设置为 bus_handle,或者如果 bus_handle 为 NULL,则该函数会查找一个子节点,其“reg”属性与 i2c-atr 设备“i2c-atr”节点下的 chan_id 匹配。

调用 i2c_atr_del_adapter() 以删除适配器。

返回

成功时返回 0,否则返回负错误代码。

void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id)

删除由 i2c_atr_add_adapter() 添加的子(“下游”)I2C 总线。如果没有添加 I2C 总线,此函数不执行任何操作。

参数

struct i2c_atr *atr

I2C ATR

u32 chan_id

要删除的适配器的索引 (0 .. max_adapters-1)

void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data)

将私有驱动数据设置到 i2c-atr 实例中。

参数

struct i2c_atr *atr

I2C ATR

void *data

指向要存储的数据的指针

void *i2c_atr_get_driver_data(struct i2c_atr *atr)

获取存储的驱动数据。

参数

struct i2c_atr *atr

I2C ATR

返回

指向存储数据的指针