1
2
3
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
15DECLARE_GLOBAL_DATA_PTR;
16
17struct tegra186_bpmp_i2c {
18 uint32_t bpmp_bus_id;
19};
20
21static 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
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
39static 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
91static int tegra186_bpmp_probe_chip(struct udevice *bus, uint chip_addr,
92 uint chip_flags)
93{
94 return 0;
95}
96
97static 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
111static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
112 .xfer = tegra186_bpmp_i2c_xfer,
113 .probe_chip = tegra186_bpmp_probe_chip,
114};
115
116static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
117 { .compatible = "nvidia,tegra186-bpmp-i2c" },
118 { }
119};
120
121U_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