uboot/drivers/i2c/tegra186_bpmp_i2c.c
<<
>>
Prefs
   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
  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/* 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
  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