1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2016, NVIDIA CORPORATION.
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <i2c.h>
9 #include <log.h>
10 #include <misc.h>
11 #include <asm/arch-tegra/bpmp_abi.h>
12 #include <asm/global_data.h>
13 #include <linux/bitops.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 struct tegra186_bpmp_i2c {
18 	uint32_t bpmp_bus_id;
19 };
20 
serialize_u16(uint8_t ** p,uint16_t val)21 static inline void serialize_u16(uint8_t **p, uint16_t val)
22 {
23 	(*p)[0] = val & 0xff;
24 	(*p)[1] = val >> 8;
25 	(*p) += 2;
26 }
27 
28 /* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
29 #define SUPPORTED_FLAGS \
30 	(I2C_M_TEN | \
31 	I2C_M_RD | \
32 	I2C_M_STOP | \
33 	I2C_M_NOSTART | \
34 	I2C_M_REV_DIR_ADDR | \
35 	I2C_M_IGNORE_NAK | \
36 	I2C_M_NO_RD_ACK | \
37 	I2C_M_RECV_LEN)
38 
tegra186_bpmp_i2c_xfer(struct udevice * dev,struct i2c_msg * msg,int nmsgs)39 static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
40 				  int nmsgs)
41 {
42 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
43 	struct mrq_i2c_request req;
44 	struct mrq_i2c_response resp;
45 	uint8_t *p;
46 	int left, i, ret;
47 
48 	req.cmd = CMD_I2C_XFER;
49 	req.xfer.bus_id = priv->bpmp_bus_id;
50 	p = &req.xfer.data_buf[0];
51 	left = ARRAY_SIZE(req.xfer.data_buf);
52 	for (i = 0; i < nmsgs; i++) {
53 		int len = 6;
54 		if (!(msg[i].flags & I2C_M_RD))
55 			len += msg[i].len;
56 		if ((len >= BIT(16)) || (len > left))
57 			return -ENOSPC;
58 
59 		if (msg[i].flags & ~SUPPORTED_FLAGS)
60 			return -EINVAL;
61 
62 		serialize_u16(&p, msg[i].addr);
63 		serialize_u16(&p, msg[i].flags);
64 		serialize_u16(&p, msg[i].len);
65 		if (!(msg[i].flags & I2C_M_RD)) {
66 			memcpy(p, msg[i].buf, msg[i].len);
67 			p += msg[i].len;
68 		}
69 	}
70 	req.xfer.data_size = p - &req.xfer.data_buf[0];
71 
72 	ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
73 			sizeof(resp));
74 	if (ret < 0)
75 		return ret;
76 
77 	p = &resp.xfer.data_buf[0];
78 	left = resp.xfer.data_size;
79 	if (left > ARRAY_SIZE(resp.xfer.data_buf))
80 		return -EINVAL;
81 	for (i = 0; i < nmsgs; i++) {
82 		if (msg[i].flags & I2C_M_RD) {
83 			memcpy(msg[i].buf, p, msg[i].len);
84 			p += msg[i].len;
85 		}
86 	}
87 
88 	return 0;
89 }
90 
tegra186_bpmp_probe_chip(struct udevice * bus,uint chip_addr,uint chip_flags)91 static int tegra186_bpmp_probe_chip(struct udevice *bus, uint chip_addr,
92 				    uint chip_flags)
93 {
94 	return 0;
95 }
96 
tegra186_bpmp_i2c_probe(struct udevice * dev)97 static int tegra186_bpmp_i2c_probe(struct udevice *dev)
98 {
99 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
100 
101 	priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
102 					    "nvidia,bpmp-bus-id", U32_MAX);
103 	if (priv->bpmp_bus_id == U32_MAX) {
104 		debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
105 		return -EINVAL;
106 	}
107 
108 	return 0;
109 }
110 
111 static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
112 	.xfer = tegra186_bpmp_i2c_xfer,
113 	.probe_chip = tegra186_bpmp_probe_chip,
114 };
115 
116 static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
117 	{ .compatible = "nvidia,tegra186-bpmp-i2c" },
118 	{ }
119 };
120 
121 U_BOOT_DRIVER(i2c_gpio) = {
122 	.name	= "tegra186_bpmp_i2c",
123 	.id	= UCLASS_I2C,
124 	.of_match = tegra186_bpmp_i2c_ids,
125 	.probe	= tegra186_bpmp_i2c_probe,
126 	.priv_auto	= sizeof(struct tegra186_bpmp_i2c),
127 	.ops	= &tegra186_bpmp_i2c_ops,
128 };
129