123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- /*
- * Copyright (c) 2016, NVIDIA CORPORATION.
- *
- * SPDX-License-Identifier: GPL-2.0
- */
- #include <common.h>
- #include <dm.h>
- #include <i2c.h>
- #include <misc.h>
- #include <asm/arch-tegra/bpmp_abi.h>
- DECLARE_GLOBAL_DATA_PTR;
- struct tegra186_bpmp_i2c {
- uint32_t bpmp_bus_id;
- };
- static inline void serialize_u16(uint8_t **p, uint16_t val)
- {
- (*p)[0] = val & 0xff;
- (*p)[1] = val >> 8;
- (*p) += 2;
- }
- /* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
- #define SUPPORTED_FLAGS \
- (I2C_M_TEN | \
- I2C_M_RD | \
- I2C_M_STOP | \
- I2C_M_NOSTART | \
- I2C_M_REV_DIR_ADDR | \
- I2C_M_IGNORE_NAK | \
- I2C_M_NO_RD_ACK | \
- I2C_M_RECV_LEN)
- static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
- int nmsgs)
- {
- struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
- struct mrq_i2c_request req;
- struct mrq_i2c_response resp;
- uint8_t *p;
- int left, i, ret;
- req.cmd = CMD_I2C_XFER;
- req.xfer.bus_id = priv->bpmp_bus_id;
- p = &req.xfer.data_buf[0];
- left = ARRAY_SIZE(req.xfer.data_buf);
- for (i = 0; i < nmsgs; i++) {
- int len = 6;
- if (!(msg[i].flags & I2C_M_RD))
- len += msg[i].len;
- if ((len >= BIT(16)) || (len > left))
- return -ENOSPC;
- if (msg[i].flags & ~SUPPORTED_FLAGS)
- return -EINVAL;
- serialize_u16(&p, msg[i].addr);
- serialize_u16(&p, msg[i].flags);
- serialize_u16(&p, msg[i].len);
- if (!(msg[i].flags & I2C_M_RD)) {
- memcpy(p, msg[i].buf, msg[i].len);
- p += msg[i].len;
- }
- }
- req.xfer.data_size = p - &req.xfer.data_buf[0];
- ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
- sizeof(resp));
- if (ret < 0)
- return ret;
- p = &resp.xfer.data_buf[0];
- left = resp.xfer.data_size;
- if (left > ARRAY_SIZE(resp.xfer.data_buf))
- return -EINVAL;
- for (i = 0; i < nmsgs; i++) {
- if (msg[i].flags & I2C_M_RD) {
- memcpy(msg[i].buf, p, msg[i].len);
- p += msg[i].len;
- }
- }
- return 0;
- }
- static int tegra186_bpmp_i2c_probe(struct udevice *dev)
- {
- struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
- priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
- "nvidia,bpmp-bus-id", U32_MAX);
- if (priv->bpmp_bus_id == U32_MAX) {
- debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
- return -ENODEV;
- }
- return 0;
- }
- static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
- .xfer = tegra186_bpmp_i2c_xfer,
- };
- static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
- { .compatible = "nvidia,tegra186-bpmp-i2c" },
- { }
- };
- U_BOOT_DRIVER(i2c_gpio) = {
- .name = "tegra186_bpmp_i2c",
- .id = UCLASS_I2C,
- .of_match = tegra186_bpmp_i2c_ids,
- .probe = tegra186_bpmp_i2c_probe,
- .priv_auto_alloc_size = sizeof(struct tegra186_bpmp_i2c),
- .ops = &tegra186_bpmp_i2c_ops,
- };
|