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
用法
在驱动程序中(通常在 probe 函数中),通过调用
i2c_atr_new()
并传递 attach/detach 回调来添加 ATR当调用 attach 回调时,选择适当的别名,在芯片中配置它,并在 alias_id 参数中返回所选别名
当调用 detach 回调时,从芯片中取消配置别名,并将别名放回池中以供以后使用
I2C ATR 函数和数据结构¶
-
enum i2c_atr_flags¶
I2C ATR 驱动程序的标志
常量
I2C_ATR_F_STATIC
ATR 不支持动态映射,使用静态映射。映射只会因设备从子总线添加或删除而添加或删除。 ATR 池必须足够大,以容纳预计添加到子总线的所有设备。
I2C_ATR_F_PASSTHROUGH
允许未映射的传入地址通过
-
struct i2c_atr_ops¶
从 ATR 到设备驱动程序的回调。
定义:
struct i2c_atr_ops {
int (*attach_addr)(struct i2c_atr *atr, u32 chan_id, u16 addr, u16 alias);
void (*detach_addr)(struct i2c_atr *atr, u32 chan_id, u16 addr);
};
成员
attach_addr
通知驱动程序有新设备连接到子总线,并为其分配了别名。 驱动程序必须配置硬件以使用该别名。
detach_addr
通知驱动程序设备已断开连接。 驱动程序必须配置硬件以停止使用该别名。
描述
所有这些函数在成功时返回 0,否则返回一个负错误代码。
-
struct i2c_atr_adap_desc¶
ATR 下游总线描述符
定义:
struct i2c_atr_adap_desc {
u32 chan_id;
struct device *parent;
struct fwnode_handle *bus_handle;
size_t num_aliases;
u16 *aliases;
};
成员
chan_id
新适配器的索引(0 .. max_adapters-1)。此值将传递给
struct i2c_atr_ops
中的回调。parent
用作新 i2c 适配器父设备的设备,或者为 NULL 以使用 i2c-atr 设备作为父设备。
bus_handle
指向适配器的 i2c 外设的 fwnode 句柄,或 NULL。
num_aliases
此适配器的私有别名池中的别名数量。如果此适配器使用 ATR 的全局别名池,则设置为零。
aliases
适配器使用的私有别名的可选数组,而不是 ATR 的全局别名池。如果 num_aliases > 0,则必须包含确切的 num_aliases 条目,否则将被忽略。
-
struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, const struct i2c_atr_ops *ops, int max_adapters, u32 flags)¶
分配和初始化 I2C ATR 助手。
参数
struct i2c_adapter *parent
父(上游)适配器
struct device *dev
充当 ATR 的设备
const struct i2c_atr_ops *ops
特定于驱动程序的回调
int max_adapters
子适配器的最大数量
u32 flags
ATR 的标志
描述
新的 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, struct i2c_atr_adap_desc *desc)¶
创建子(“下游”)I2C 总线。
参数
struct i2c_atr *atr
I2C ATR
struct i2c_atr_adap_desc *desc
ATR 适配器描述符
描述
调用此函数后,将出现一条新的 i2c 总线。 在下游总线上添加和删除设备将导致调用 i2c_atr_ops->attach_client
和 i2c_atr_ops->detach_client
回调,供驱动程序为设备分配别名。
适配器的 fwnode 设置为 bus_handle,或者如果 bus_handle 为 NULL,则该函数会在 i2c-atr 设备的“i2c-atr”节点下查找其 ‘reg’ 属性与 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
返回
指向存储数据的指针