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, 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 -ENODEV; 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 }; 120