mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
media: i2c: add I2C Address Translator (ATR) support
An ATR is a device that looks similar to an i2c-mux: it has an I2C slave "upstream" port and N master "downstream" ports, and forwards transactions from upstream to the appropriate downstream port. But it is different in that the forwarded transaction has a different slave address. The address used on the upstream bus is called the "alias" and is (potentially) different from the physical slave address of the downstream chip. Add a helper file (just like i2c-mux.c for a mux or switch) to allow implementing ATR features in a device driver. The helper takes care of adapter creation/destruction and translates addresses at each transaction. Signed-off-by: Luca Ceresoli <luca@lucaceresoli.net> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Wolfram Sang <wsa@kernel.org> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
86251cf8fd
commit
a076a860ac
96
Documentation/i2c/i2c-address-translators.rst
Normal file
96
Documentation/i2c/i2c-address-translators.rst
Normal file
@@ -0,0 +1,96 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=======================
|
||||
I2C Address Translators
|
||||
=======================
|
||||
|
||||
Author: Luca Ceresoli <luca@lucaceresoli.net>
|
||||
Author: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
An I2C Address Translator (ATR) is a device with an I2C slave parent
|
||||
("upstream") port and N I2C master child ("downstream") ports, and
|
||||
forwards transactions from upstream to the appropriate downstream port
|
||||
with a modified slave address. The address used on the parent bus is
|
||||
called the "alias" and is (potentially) different from the physical
|
||||
slave address of the child bus. Address translation is done by the
|
||||
hardware.
|
||||
|
||||
An ATR looks similar to an i2c-mux except:
|
||||
- the address on the parent and child busses can be different
|
||||
- there is normally no need to select the child port; the alias used on the
|
||||
parent bus implies it
|
||||
|
||||
The ATR functionality can be provided by a chip with many other features.
|
||||
The kernel i2c-atr provides a helper to implement an ATR within a driver.
|
||||
|
||||
The ATR creates a new I2C "child" adapter on each child bus. Adding
|
||||
devices on the child bus ends up in invoking the driver code to select
|
||||
an available alias. Maintaining an appropriate pool of available aliases
|
||||
and picking one for each new device is up to the driver implementer. The
|
||||
ATR maintains a table of currently assigned alias and uses it to modify
|
||||
all I2C transactions directed to devices on the child buses.
|
||||
|
||||
A typical example follows.
|
||||
|
||||
Topology::
|
||||
|
||||
Slave X @ 0x10
|
||||
.-----. |
|
||||
.-----. | |---+---- B
|
||||
| CPU |--A--| ATR |
|
||||
`-----' | |---+---- C
|
||||
`-----' |
|
||||
Slave Y @ 0x10
|
||||
|
||||
Alias table:
|
||||
|
||||
A, B and C are three physical I2C busses, electrically independent from
|
||||
each other. The ATR receives the transactions initiated on bus A and
|
||||
propagates them on bus B or bus C or none depending on the device address
|
||||
in the transaction and based on the alias table.
|
||||
|
||||
Alias table:
|
||||
|
||||
.. table::
|
||||
|
||||
=============== =====
|
||||
Client Alias
|
||||
=============== =====
|
||||
X (bus B, 0x10) 0x20
|
||||
Y (bus C, 0x10) 0x30
|
||||
=============== =====
|
||||
|
||||
Transaction:
|
||||
|
||||
- Slave X driver requests a transaction (on adapter B), slave address 0x10
|
||||
- ATR driver finds slave X is on bus B and has alias 0x20, rewrites
|
||||
messages with address 0x20, forwards to adapter A
|
||||
- Physical I2C transaction on bus A, slave address 0x20
|
||||
- ATR chip detects transaction on address 0x20, finds it in table,
|
||||
propagates transaction on bus B with address translated to 0x10,
|
||||
keeps clock streched on bus A waiting for reply
|
||||
- Slave X chip (on bus B) detects transaction at its own physical
|
||||
address 0x10 and replies normally
|
||||
- ATR chip stops clock stretching and forwards reply on bus A,
|
||||
with address translated back to 0x20
|
||||
- ATR driver receives the reply, rewrites messages with address 0x10
|
||||
as they were initially
|
||||
- Slave X driver gets back the msgs[], with reply and address 0x10
|
||||
|
||||
Usage:
|
||||
|
||||
1. In the driver (typically in the probe function) add an ATR by
|
||||
calling i2c_atr_new() passing attach/detach callbacks
|
||||
2. When the attach callback is called pick an appropriate alias,
|
||||
configure it in the chip and return the chosen alias in the
|
||||
alias_id parameter
|
||||
3. When the detach callback is called, deconfigure the alias from
|
||||
the chip and put the alias back in the pool for later usage
|
||||
|
||||
I2C ATR functions and data structures
|
||||
-------------------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/i2c-atr.h
|
||||
@@ -18,6 +18,7 @@ Introduction
|
||||
i2c-topology
|
||||
muxes/i2c-mux-gpio
|
||||
i2c-sysfs
|
||||
i2c-address-translators
|
||||
|
||||
Writing device drivers
|
||||
======================
|
||||
|
||||
@@ -9670,6 +9670,14 @@ L: linux-acpi@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/i2c-core-acpi.c
|
||||
|
||||
I2C ADDRESS TRANSLATOR (ATR)
|
||||
M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
R: Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/i2c-atr.c
|
||||
F: include/linux/i2c-atr.h
|
||||
|
||||
I2C CONTROLLER DRIVER FOR NVIDIA GPU
|
||||
M: Ajay Gupta <ajayg@nvidia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
|
||||
@@ -71,6 +71,15 @@ config I2C_MUX
|
||||
|
||||
source "drivers/i2c/muxes/Kconfig"
|
||||
|
||||
config I2C_ATR
|
||||
tristate "I2C Address Translator (ATR) support"
|
||||
help
|
||||
Enable support for I2C Address Translator (ATR) chips.
|
||||
|
||||
An ATR allows accessing multiple I2C busses from a single
|
||||
physical bus via address translation instead of bus selection as
|
||||
i2c-muxes do.
|
||||
|
||||
config I2C_HELPER_AUTO
|
||||
bool "Autoselect pertinent helper modules"
|
||||
default y
|
||||
|
||||
@@ -13,6 +13,7 @@ i2c-core-$(CONFIG_OF) += i2c-core-of.o
|
||||
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
|
||||
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
|
||||
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
||||
obj-$(CONFIG_I2C_ATR) += i2c-atr.o
|
||||
obj-y += algos/ busses/ muxes/
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
|
||||
|
||||
710
drivers/i2c/i2c-atr.c
Normal file
710
drivers/i2c/i2c-atr.c
Normal file
File diff suppressed because it is too large
Load Diff
116
include/linux/i2c-atr.h
Normal file
116
include/linux/i2c-atr.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* I2C Address Translator
|
||||
*
|
||||
* Copyright (c) 2019,2022 Luca Ceresoli <luca@lucaceresoli.net>
|
||||
* Copyright (c) 2022,2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
*
|
||||
* Based on i2c-mux.h
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_I2C_ATR_H
|
||||
#define _LINUX_I2C_ATR_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
struct fwnode_handle;
|
||||
struct i2c_atr;
|
||||
|
||||
/**
|
||||
* struct i2c_atr_ops - Callbacks from ATR to the device driver.
|
||||
* @attach_client: Notify the driver of a new device connected on a child
|
||||
* bus, with the alias assigned to it. The driver must
|
||||
* configure the hardware to use the alias.
|
||||
* @detach_client: Notify the driver of a device getting disconnected. The
|
||||
* driver must configure the hardware to stop using the
|
||||
* alias.
|
||||
*
|
||||
* All these functions return 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* i2c_atr_new() - Allocate and initialize an I2C ATR helper.
|
||||
* @parent: The parent (upstream) adapter
|
||||
* @dev: The device acting as an ATR
|
||||
* @ops: Driver-specific callbacks
|
||||
* @max_adapters: Maximum number of child adapters
|
||||
*
|
||||
* The new ATR helper is connected to the parent adapter but has no child
|
||||
* adapters. Call i2c_atr_add_adapter() to add some.
|
||||
*
|
||||
* Call i2c_atr_delete() to remove.
|
||||
*
|
||||
* Return: pointer to the new ATR helper object, or ERR_PTR
|
||||
*/
|
||||
struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev,
|
||||
const struct i2c_atr_ops *ops, int max_adapters);
|
||||
|
||||
/**
|
||||
* i2c_atr_delete - Delete an I2C ATR helper.
|
||||
* @atr: I2C ATR helper to be deleted.
|
||||
*
|
||||
* Precondition: all the adapters added with i2c_atr_add_adapter() must be
|
||||
* removed by calling i2c_atr_del_adapter().
|
||||
*/
|
||||
void i2c_atr_delete(struct i2c_atr *atr);
|
||||
|
||||
/**
|
||||
* i2c_atr_add_adapter - Create a child ("downstream") I2C bus.
|
||||
* @atr: The I2C ATR
|
||||
* @chan_id: Index of the new adapter (0 .. max_adapters-1). This value is
|
||||
* passed to the callbacks in `struct i2c_atr_ops`.
|
||||
* @adapter_parent: The device used as the parent of the new i2c adapter, or NULL
|
||||
* to use the i2c-atr device as the parent.
|
||||
* @bus_handle: The fwnode handle that points to the adapter's i2c
|
||||
* peripherals, or NULL.
|
||||
*
|
||||
* After calling this function a new i2c bus will appear. Adding and removing
|
||||
* devices on the downstream bus will result in calls to the
|
||||
* &i2c_atr_ops->attach_client and &i2c_atr_ops->detach_client callbacks for the
|
||||
* driver to assign an alias to the device.
|
||||
*
|
||||
* The adapter's fwnode is set to @bus_handle, or if @bus_handle is NULL the
|
||||
* function looks for a child node whose 'reg' property matches the chan_id
|
||||
* under the i2c-atr device's 'i2c-atr' node.
|
||||
*
|
||||
* Call i2c_atr_del_adapter() to remove the adapter.
|
||||
*
|
||||
* Return: 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
|
||||
struct device *adapter_parent,
|
||||
struct fwnode_handle *bus_handle);
|
||||
|
||||
/**
|
||||
* i2c_atr_del_adapter - Remove a child ("downstream") I2C bus added by
|
||||
* i2c_atr_add_adapter(). If no I2C bus has been added
|
||||
* this function is a no-op.
|
||||
* @atr: The I2C ATR
|
||||
* @chan_id: Index of the adapter to be removed (0 .. max_adapters-1)
|
||||
*/
|
||||
void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id);
|
||||
|
||||
/**
|
||||
* i2c_atr_set_driver_data - Set private driver data to the i2c-atr instance.
|
||||
* @atr: The I2C ATR
|
||||
* @data: Pointer to the data to store
|
||||
*/
|
||||
void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data);
|
||||
|
||||
/**
|
||||
* i2c_atr_get_driver_data - Get the stored drive data.
|
||||
* @atr: The I2C ATR
|
||||
*
|
||||
* Return: Pointer to the stored data
|
||||
*/
|
||||
void *i2c_atr_get_driver_data(struct i2c_atr *atr);
|
||||
|
||||
#endif /* _LINUX_I2C_ATR_H */
|
||||
Reference in New Issue
Block a user