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