xref: /openbmc/u-boot/drivers/i2c/tegra186_bpmp_i2c.c (revision d117d8f19b0625f88309e47a8a32c2faa384dddc)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
234f1c9feSStephen Warren /*
334f1c9feSStephen Warren  * Copyright (c) 2016, NVIDIA CORPORATION.
434f1c9feSStephen Warren  */
534f1c9feSStephen Warren 
634f1c9feSStephen Warren #include <common.h>
734f1c9feSStephen Warren #include <dm.h>
834f1c9feSStephen Warren #include <i2c.h>
934f1c9feSStephen Warren #include <misc.h>
1034f1c9feSStephen Warren #include <asm/arch-tegra/bpmp_abi.h>
1134f1c9feSStephen Warren 
1234f1c9feSStephen Warren DECLARE_GLOBAL_DATA_PTR;
1334f1c9feSStephen Warren 
1434f1c9feSStephen Warren struct tegra186_bpmp_i2c {
1534f1c9feSStephen Warren 	uint32_t bpmp_bus_id;
1634f1c9feSStephen Warren };
1734f1c9feSStephen Warren 
serialize_u16(uint8_t ** p,uint16_t val)1834f1c9feSStephen Warren static inline void serialize_u16(uint8_t **p, uint16_t val)
1934f1c9feSStephen Warren {
2034f1c9feSStephen Warren 	(*p)[0] = val & 0xff;
2134f1c9feSStephen Warren 	(*p)[1] = val >> 8;
2234f1c9feSStephen Warren 	(*p) += 2;
2334f1c9feSStephen Warren }
2434f1c9feSStephen Warren 
2534f1c9feSStephen Warren /* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
2634f1c9feSStephen Warren #define SUPPORTED_FLAGS \
2734f1c9feSStephen Warren 	(I2C_M_TEN | \
2834f1c9feSStephen Warren 	I2C_M_RD | \
2934f1c9feSStephen Warren 	I2C_M_STOP | \
3034f1c9feSStephen Warren 	I2C_M_NOSTART | \
3134f1c9feSStephen Warren 	I2C_M_REV_DIR_ADDR | \
3234f1c9feSStephen Warren 	I2C_M_IGNORE_NAK | \
3334f1c9feSStephen Warren 	I2C_M_NO_RD_ACK | \
3434f1c9feSStephen Warren 	I2C_M_RECV_LEN)
3534f1c9feSStephen Warren 
tegra186_bpmp_i2c_xfer(struct udevice * dev,struct i2c_msg * msg,int nmsgs)3634f1c9feSStephen Warren static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
3734f1c9feSStephen Warren 				  int nmsgs)
3834f1c9feSStephen Warren {
3934f1c9feSStephen Warren 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
4034f1c9feSStephen Warren 	struct mrq_i2c_request req;
4134f1c9feSStephen Warren 	struct mrq_i2c_response resp;
4234f1c9feSStephen Warren 	uint8_t *p;
4334f1c9feSStephen Warren 	int left, i, ret;
4434f1c9feSStephen Warren 
4534f1c9feSStephen Warren 	req.cmd = CMD_I2C_XFER;
4634f1c9feSStephen Warren 	req.xfer.bus_id = priv->bpmp_bus_id;
4734f1c9feSStephen Warren 	p = &req.xfer.data_buf[0];
4834f1c9feSStephen Warren 	left = ARRAY_SIZE(req.xfer.data_buf);
4934f1c9feSStephen Warren 	for (i = 0; i < nmsgs; i++) {
5034f1c9feSStephen Warren 		int len = 6;
5134f1c9feSStephen Warren 		if (!(msg[i].flags & I2C_M_RD))
5234f1c9feSStephen Warren 			len += msg[i].len;
5334f1c9feSStephen Warren 		if ((len >= BIT(16)) || (len > left))
5434f1c9feSStephen Warren 			return -ENOSPC;
5534f1c9feSStephen Warren 
5634f1c9feSStephen Warren 		if (msg[i].flags & ~SUPPORTED_FLAGS)
5734f1c9feSStephen Warren 			return -EINVAL;
5834f1c9feSStephen Warren 
5934f1c9feSStephen Warren 		serialize_u16(&p, msg[i].addr);
6034f1c9feSStephen Warren 		serialize_u16(&p, msg[i].flags);
6134f1c9feSStephen Warren 		serialize_u16(&p, msg[i].len);
6234f1c9feSStephen Warren 		if (!(msg[i].flags & I2C_M_RD)) {
6334f1c9feSStephen Warren 			memcpy(p, msg[i].buf, msg[i].len);
6434f1c9feSStephen Warren 			p += msg[i].len;
6534f1c9feSStephen Warren 		}
6634f1c9feSStephen Warren 	}
6734f1c9feSStephen Warren 	req.xfer.data_size = p - &req.xfer.data_buf[0];
6834f1c9feSStephen Warren 
6934f1c9feSStephen Warren 	ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
7034f1c9feSStephen Warren 			sizeof(resp));
7134f1c9feSStephen Warren 	if (ret < 0)
7234f1c9feSStephen Warren 		return ret;
7334f1c9feSStephen Warren 
7434f1c9feSStephen Warren 	p = &resp.xfer.data_buf[0];
7534f1c9feSStephen Warren 	left = resp.xfer.data_size;
7634f1c9feSStephen Warren 	if (left > ARRAY_SIZE(resp.xfer.data_buf))
7734f1c9feSStephen Warren 		return -EINVAL;
7834f1c9feSStephen Warren 	for (i = 0; i < nmsgs; i++) {
7934f1c9feSStephen Warren 		if (msg[i].flags & I2C_M_RD) {
8034f1c9feSStephen Warren 			memcpy(msg[i].buf, p, msg[i].len);
8134f1c9feSStephen Warren 			p += msg[i].len;
8234f1c9feSStephen Warren 		}
8334f1c9feSStephen Warren 	}
8434f1c9feSStephen Warren 
8534f1c9feSStephen Warren 	return 0;
8634f1c9feSStephen Warren }
8734f1c9feSStephen Warren 
tegra186_bpmp_probe_chip(struct udevice * bus,uint chip_addr,uint chip_flags)88*22ecff59SJean-Jacques Hiblot static int tegra186_bpmp_probe_chip(struct udevice *bus, uint chip_addr,
89*22ecff59SJean-Jacques Hiblot 				    uint chip_flags)
90*22ecff59SJean-Jacques Hiblot {
91*22ecff59SJean-Jacques Hiblot 	return 0;
92*22ecff59SJean-Jacques Hiblot }
93*22ecff59SJean-Jacques Hiblot 
tegra186_bpmp_i2c_probe(struct udevice * dev)9434f1c9feSStephen Warren static int tegra186_bpmp_i2c_probe(struct udevice *dev)
9534f1c9feSStephen Warren {
9634f1c9feSStephen Warren 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
9734f1c9feSStephen Warren 
98e160f7d4SSimon Glass 	priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
9934f1c9feSStephen Warren 					    "nvidia,bpmp-bus-id", U32_MAX);
10034f1c9feSStephen Warren 	if (priv->bpmp_bus_id == U32_MAX) {
10134f1c9feSStephen Warren 		debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
1027c84319aSSimon Glass 		return -EINVAL;
10334f1c9feSStephen Warren 	}
10434f1c9feSStephen Warren 
10534f1c9feSStephen Warren 	return 0;
10634f1c9feSStephen Warren }
10734f1c9feSStephen Warren 
10834f1c9feSStephen Warren static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
10934f1c9feSStephen Warren 	.xfer = tegra186_bpmp_i2c_xfer,
110*22ecff59SJean-Jacques Hiblot 	.probe_chip = tegra186_bpmp_probe_chip,
11134f1c9feSStephen Warren };
11234f1c9feSStephen Warren 
11334f1c9feSStephen Warren static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
11434f1c9feSStephen Warren 	{ .compatible = "nvidia,tegra186-bpmp-i2c" },
11534f1c9feSStephen Warren 	{ }
11634f1c9feSStephen Warren };
11734f1c9feSStephen Warren 
11834f1c9feSStephen Warren U_BOOT_DRIVER(i2c_gpio) = {
11934f1c9feSStephen Warren 	.name	= "tegra186_bpmp_i2c",
12034f1c9feSStephen Warren 	.id	= UCLASS_I2C,
12134f1c9feSStephen Warren 	.of_match = tegra186_bpmp_i2c_ids,
12234f1c9feSStephen Warren 	.probe	= tegra186_bpmp_i2c_probe,
12334f1c9feSStephen Warren 	.priv_auto_alloc_size = sizeof(struct tegra186_bpmp_i2c),
12434f1c9feSStephen Warren 	.ops	= &tegra186_bpmp_i2c_ops,
12534f1c9feSStephen Warren };
126