GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,46 @@
config I2C_MUX
bool "Support I2C multiplexers"
depends on DM_I2C
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config SPL_I2C_MUX
bool "Support I2C multiplexers on SPL"
depends on I2C_MUX
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config I2C_ARB_GPIO_CHALLENGE
bool "GPIO-based I2C arbitration"
depends on I2C_MUX
help
If you say yes to this option, support will be included for an
I2C multimaster arbitration scheme using GPIOs and a challenge &
response mechanism where masters have to claim the bus by asserting
a GPIO.
config I2C_MUX_PCA954x
tristate "TI PCA954x I2C Mux/switches"
depends on I2C_MUX
help
If you say yes here you get support for the TI PCA954x I2C mux/switch
devices. It is x width I2C multiplexer which enables to partitioning
I2C bus and connect multiple devices with the same address to the same
I2C controller where driver handles proper routing to target i2c
device. Supported chips are PCA9543, PCA9544, PCA9547, PCA9548 and
PCA9646.
config I2C_MUX_GPIO
tristate "GPIO-based I2C multiplexer"
depends on I2C_MUX && DM_GPIO
help
If you say yes to this option, support will be included for
a GPIO based I2C multiplexer. This driver provides access to
I2C busses connected through a MUX, which is controlled
through GPIO pins.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2015 Google, Inc
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o
obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
struct i2c_arbitrator_priv {
struct gpio_desc ap_claim;
struct gpio_desc ec_claim;
uint slew_delay_us;
uint wait_retry_ms;
uint wait_free_ms;
};
int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
ret = dm_gpio_set_value(&priv->ap_claim, 0);
udelay(priv->slew_delay_us);
return ret;
}
int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
unsigned start;
int ret;
debug("%s: %s\n", __func__, mux->name);
/* Start a round of trying to claim the bus */
start = get_timer(0);
do {
unsigned start_retry;
int waiting = 0;
/* Indicate that we want to claim the bus */
ret = dm_gpio_set_value(&priv->ap_claim, 1);
if (ret)
goto err;
udelay(priv->slew_delay_us);
/* Wait for the EC to release it */
start_retry = get_timer(0);
while (get_timer(start_retry) < priv->wait_retry_ms) {
ret = dm_gpio_get_value(&priv->ec_claim);
if (ret < 0) {
goto err;
} else if (!ret) {
/* We got it, so return */
return 0;
}
if (!waiting)
waiting = 1;
}
/* It didn't release, so give up, wait, and try again */
ret = dm_gpio_set_value(&priv->ap_claim, 0);
if (ret)
goto err;
mdelay(priv->wait_retry_ms);
} while (get_timer(start) < priv->wait_free_ms);
/* Give up, release our claim */
printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
ret = -ETIMEDOUT;
ret = 0;
err:
return ret;
}
static int i2c_arbitrator_probe(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev_of_offset(dev);
int ret;
debug("%s: %s\n", __func__, dev->name);
priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
1000;
priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
1000;
ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
GPIOD_IS_OUT);
if (ret)
goto err;
ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
GPIOD_IS_IN);
if (ret)
goto err_ec_gpio;
return 0;
err_ec_gpio:
dm_gpio_free(dev, &priv->ap_claim);
err:
debug("%s: ret=%d\n", __func__, ret);
return ret;
}
static int i2c_arbitrator_remove(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
dm_gpio_free(dev, &priv->ap_claim);
dm_gpio_free(dev, &priv->ec_claim);
return 0;
}
static const struct i2c_mux_ops i2c_arbitrator_ops = {
.select = i2c_arbitrator_select,
.deselect = i2c_arbitrator_deselect,
};
static const struct udevice_id i2c_arbitrator_ids[] = {
{ .compatible = "i2c-arb-gpio-challenge" },
{ }
};
U_BOOT_DRIVER(i2c_arbitrator) = {
.name = "i2c_arbitrator",
.id = UCLASS_I2C_MUX,
.of_match = i2c_arbitrator_ids,
.probe = i2c_arbitrator_probe,
.remove = i2c_arbitrator_remove,
.ops = &i2c_arbitrator_ops,
.priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
};
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* I2C multiplexer using GPIO API
*
* Copyright 2017 NXP
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <fdtdec.h>
#include <i2c.h>
#include <linux/errno.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct i2c_mux_gpio_priv - private data for i2c mux gpio
*
* @values: the reg value of each child node
* @n_values: num of regs
* @gpios: the mux-gpios array
* @n_gpios: num of gpios in mux-gpios
* @idle: the value of idle-state
*/
struct i2c_mux_gpio_priv {
u32 *values;
int n_values;
struct gpio_desc *gpios;
int n_gpios;
u32 idle;
};
static int i2c_mux_gpio_select(struct udevice *dev, struct udevice *bus,
uint channel)
{
struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
int i, ret;
for (i = 0; i < priv->n_gpios; i++) {
ret = dm_gpio_set_value(&priv->gpios[i], (channel >> i) & 1);
if (ret)
return ret;
}
return 0;
}
static int i2c_mux_gpio_deselect(struct udevice *dev, struct udevice *bus,
uint channel)
{
struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
int i, ret;
for (i = 0; i < priv->n_gpios; i++) {
ret = dm_gpio_set_value(&priv->gpios[i], (priv->idle >> i) & 1);
if (ret)
return ret;
}
return 0;
}
static int i2c_mux_gpio_probe(struct udevice *dev)
{
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(dev);
struct i2c_mux_gpio_priv *mux = dev_get_priv(dev);
struct gpio_desc *gpios;
u32 *values;
int i = 0, subnode, ret;
mux->n_values = fdtdec_get_child_count(fdt, node);
values = devm_kzalloc(dev, sizeof(*mux->values) * mux->n_values,
GFP_KERNEL);
if (!values) {
dev_err(dev, "Cannot alloc values array");
return -ENOMEM;
}
fdt_for_each_subnode(subnode, fdt, node) {
*(values + i) = fdtdec_get_uint(fdt, subnode, "reg", -1);
i++;
}
mux->values = values;
mux->idle = fdtdec_get_uint(fdt, node, "idle-state", -1);
mux->n_gpios = gpio_get_list_count(dev, "mux-gpios");
if (mux->n_gpios < 0) {
dev_err(dev, "Missing mux-gpios property\n");
return -EINVAL;
}
gpios = devm_kzalloc(dev, sizeof(struct gpio_desc) * mux->n_gpios,
GFP_KERNEL);
if (!gpios) {
dev_err(dev, "Cannot allocate gpios array\n");
return -ENOMEM;
}
ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
if (ret <= 0) {
dev_err(dev, "Failed to request mux-gpios\n");
return ret;
}
mux->gpios = gpios;
return 0;
}
static const struct i2c_mux_ops i2c_mux_gpio_ops = {
.select = i2c_mux_gpio_select,
.deselect = i2c_mux_gpio_deselect,
};
static const struct udevice_id i2c_mux_gpio_ids[] = {
{ .compatible = "i2c-mux-gpio", },
{}
};
U_BOOT_DRIVER(i2c_mux_gpio) = {
.name = "i2c_mux_gpio",
.id = UCLASS_I2C_MUX,
.of_match = i2c_mux_gpio_ids,
.ops = &i2c_mux_gpio_ops,
.probe = i2c_mux_gpio_probe,
.priv_auto_alloc_size = sizeof(struct i2c_mux_gpio_priv),
};
@@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <dm/lists.h>
#include <dm/root.h>
/**
* struct i2c_mux: Information the uclass stores about an I2C mux
*
* @selected: Currently selected mux, or -1 for none
* @i2c_bus: I2C bus to use for communcation
*/
struct i2c_mux {
int selected;
struct udevice *i2c_bus;
};
/**
* struct i2c_mux_bus: Information about each bus the mux controls
*
* @channel: Channel number used to select this bus
*/
struct i2c_mux_bus {
uint channel;
};
/* Find out the mux channel number */
static int i2c_mux_child_post_bind(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
int channel;
channel = dev_read_u32_default(dev, "reg", -1);
if (channel < 0)
return -EINVAL;
plat->channel = channel;
return 0;
}
/* Find the I2C buses selected by this mux */
static int i2c_mux_post_bind(struct udevice *mux)
{
ofnode node;
int ret;
debug("%s: %s\n", __func__, mux->name);
/*
* There is no compatible string in the sub-nodes, so we must manually
* bind these
*/
dev_for_each_subnode(node, mux) {
struct udevice *dev;
const char *name;
const char *arrow = "->";
char *full_name;
int parent_name_len, arrow_len, mux_name_len, name_len;
name = ofnode_get_name(node);
/* Calculate lenghts of strings */
parent_name_len = strlen(mux->parent->name);
arrow_len = strlen(arrow);
mux_name_len = strlen(mux->name);
name_len = strlen(name);
full_name = calloc(1, parent_name_len + arrow_len +
mux_name_len + arrow_len + name_len + 1);
if (!full_name)
return -ENOMEM;
/* Compose bus name */
strcat(full_name, mux->parent->name);
strcat(full_name, arrow);
strcat(full_name, mux->name);
strcat(full_name, arrow);
strcat(full_name, name);
ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv",
full_name, node, &dev);
debug(" - bind ret=%d, %s, req_seq %d\n", ret,
dev ? dev->name : NULL, dev->req_seq);
if (ret)
return ret;
}
return 0;
}
/* Set up the mux ready for use */
static int i2c_mux_post_probe(struct udevice *mux)
{
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
priv->selected = -1;
/* if parent is of i2c uclass already, we'll take that, otherwise
* look if we find an i2c-parent phandle
*/
if (UCLASS_I2C == device_get_uclass_id(mux->parent)) {
priv->i2c_bus = dev_get_parent(mux);
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus,
priv->i2c_bus->name);
return 0;
}
ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
&priv->i2c_bus);
if (ret)
return ret;
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
return 0;
}
int i2c_mux_select(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->select)
return -ENOSYS;
return ops->select(mux, dev, plat->channel);
}
int i2c_mux_deselect(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->deselect)
return -ENOSYS;
return ops->deselect(mux, dev, plat->channel);
}
static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret, ret2;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
uint chip_flags)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->probe_chip)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->xfer)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static const struct dm_i2c_ops i2c_mux_bus_ops = {
.xfer = i2c_mux_bus_xfer,
.probe_chip = i2c_mux_bus_probe,
.set_bus_speed = i2c_mux_bus_set_bus_speed,
};
U_BOOT_DRIVER(i2c_mux_bus) = {
.name = "i2c_mux_bus_drv",
.id = UCLASS_I2C,
.ops = &i2c_mux_bus_ops,
};
UCLASS_DRIVER(i2c_mux) = {
.id = UCLASS_I2C_MUX,
.name = "i2c_mux",
.post_bind = i2c_mux_post_bind,
.post_probe = i2c_mux_post_probe,
.per_device_auto_alloc_size = sizeof(struct i2c_mux),
.per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
.child_post_bind = i2c_mux_child_post_bind,
};
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 - 2016 Xilinx, Inc.
* Copyright (C) 2017 National Instruments Corp
* Written by Michal Simek
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm-generic/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
enum pca_type {
PCA9543,
PCA9544,
PCA9547,
PCA9548,
PCA9646
};
struct chip_desc {
u8 enable; /* Enable mask in ctl register (used for muxes only) */
enum muxtype {
pca954x_ismux = 0,
pca954x_isswi,
} muxtype;
u32 width;
};
struct pca954x_priv {
u32 addr; /* I2C mux address */
u32 width; /* I2C mux width - number of busses */
struct gpio_desc gpio_mux_reset;
};
static const struct chip_desc chips[] = {
[PCA9543] = {
.muxtype = pca954x_isswi,
.width = 2,
},
[PCA9544] = {
.enable = 0x4,
.muxtype = pca954x_ismux,
.width = 4,
},
[PCA9547] = {
.enable = 0x8,
.muxtype = pca954x_ismux,
.width = 8,
},
[PCA9548] = {
.muxtype = pca954x_isswi,
.width = 8,
},
[PCA9646] = {
.muxtype = pca954x_isswi,
.width = 4,
},
};
static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
uchar byte = 0;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static int pca954x_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
uchar byte;
if (chip->muxtype == pca954x_ismux)
byte = channel | chip->enable;
else
byte = 1 << channel;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static const struct i2c_mux_ops pca954x_ops = {
.select = pca954x_select,
.deselect = pca954x_deselect,
};
static const struct udevice_id pca954x_ids[] = {
{ .compatible = "nxp,pca9543", .data = PCA9543 },
{ .compatible = "nxp,pca9544", .data = PCA9544 },
{ .compatible = "nxp,pca9547", .data = PCA9547 },
{ .compatible = "nxp,pca9548", .data = PCA9548 },
{ .compatible = "nxp,pca9646", .data = PCA9646 },
{ }
};
static int pca954x_ofdata_to_platdata(struct udevice *dev)
{
struct pca954x_priv *priv = dev_get_priv(dev);
const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
priv->addr = dev_read_u32_default(dev, "reg", 0);
if (!priv->addr) {
debug("MUX not found\n");
return -ENODEV;
}
priv->width = chip->width;
if (!priv->width) {
debug("No I2C MUX width specified\n");
return -EINVAL;
}
debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
return 0;
}
static int pca954x_probe(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
int err;
err = gpio_request_by_name(dev, "reset-gpios", 0,
&priv->gpio_mux_reset, GPIOD_IS_OUT);
/* it's optional so only bail if we get a real error */
if (err && (err != -ENOENT))
return err;
/* dm will take care of polarity */
if (dm_gpio_is_valid(&priv->gpio_mux_reset))
dm_gpio_set_value(&priv->gpio_mux_reset, 0);
}
return 0;
}
static int pca954x_remove(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
if (dm_gpio_is_valid(&priv->gpio_mux_reset))
dm_gpio_free(dev, &priv->gpio_mux_reset);
}
return 0;
}
U_BOOT_DRIVER(pca954x) = {
.name = "pca954x",
.id = UCLASS_I2C_MUX,
.of_match = pca954x_ids,
.probe = pca954x_probe,
.remove = pca954x_remove,
.ops = &pca954x_ops,
.ofdata_to_platdata = pca954x_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct pca954x_priv),
};