uboot/drivers/power/pmic/i2c_pmic_emul.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  Copyright (C) 2015 Samsung Electronics
   4 *  Przemyslaw Marczak  <p.marczak@samsung.com>
   5 */
   6
   7#include <common.h>
   8#include <errno.h>
   9#include <dm.h>
  10#include <i2c.h>
  11#include <power/pmic.h>
  12#include <power/sandbox_pmic.h>
  13
  14/**
  15 * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC
  16 *
  17 * @rw_reg: PMICs register of the chip I/O transaction
  18 * @reg:    PMICs registers array
  19 */
  20struct sandbox_i2c_pmic_plat_data {
  21        u8 rw_reg, rw_idx;
  22        u8 reg_count;
  23        u8 trans_len;
  24        u8 buf_size;
  25        u8 *reg;
  26};
  27
  28static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip,
  29                                      uchar *buffer, int len)
  30{
  31        struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
  32
  33        if (plat->rw_idx + len > plat->buf_size) {
  34                pr_err("Request exceeds PMIC register range! Max register: %#x",
  35                      plat->reg_count);
  36                return -EFAULT;
  37        }
  38
  39        debug("Read PMIC: %#x at register: %#x idx: %#x count: %d\n",
  40              (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len);
  41
  42        memcpy(buffer, plat->reg + plat->rw_idx, len);
  43
  44        return 0;
  45}
  46
  47static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip,
  48                                       uchar *buffer, int len,
  49                                       bool next_is_read)
  50{
  51        struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
  52
  53        /* Probe only */
  54        if (!len)
  55                return 0;
  56
  57        /* Set PMIC register for I/O */
  58        plat->rw_reg = *buffer;
  59        plat->rw_idx = plat->rw_reg * plat->trans_len;
  60
  61        debug("Write PMIC: %#x at register: %#x idx: %#x count: %d\n",
  62              (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len);
  63
  64        /* For read operation, set (write) only chip reg */
  65        if (next_is_read)
  66                return 0;
  67
  68        buffer++;
  69        len--;
  70
  71        if (plat->rw_idx + len > plat->buf_size) {
  72                pr_err("Request exceeds PMIC register range! Max register: %#x",
  73                      plat->reg_count);
  74        }
  75
  76        memcpy(plat->reg + plat->rw_idx, buffer, len);
  77
  78        return 0;
  79}
  80
  81static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg,
  82                                 int nmsgs)
  83{
  84        int ret = 0;
  85
  86        for (; nmsgs > 0; nmsgs--, msg++) {
  87                bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
  88                if (msg->flags & I2C_M_RD) {
  89                        ret = sandbox_i2c_pmic_read_data(emul, msg->addr,
  90                                                         msg->buf, msg->len);
  91                } else {
  92                        ret = sandbox_i2c_pmic_write_data(emul, msg->addr,
  93                                                          msg->buf, msg->len,
  94                                                          next_is_read);
  95                }
  96
  97                if (ret)
  98                        break;
  99        }
 100
 101        return ret;
 102}
 103
 104static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul)
 105{
 106        struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
 107        struct udevice *pmic_dev = i2c_emul_get_device(emul);
 108        struct uc_pmic_priv *priv = dev_get_uclass_priv(pmic_dev);
 109        const u8 *reg_defaults;
 110
 111        debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__);
 112        plat->reg_count = pmic_reg_count(pmic_dev);
 113        plat->trans_len = priv->trans_len;
 114        plat->buf_size = plat->reg_count * plat->trans_len;
 115
 116        plat->reg = calloc(1, plat->buf_size);
 117        if (!plat->reg) {
 118                debug("Canot allocate memory (%d B) for PMIC I2C emulation!\n",
 119                      plat->buf_size);
 120                return -ENOMEM;
 121        }
 122
 123        reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults",
 124                                             plat->buf_size);
 125
 126        if (!reg_defaults) {
 127                pr_err("Property \"reg-defaults\" not found for device: %s!",
 128                      emul->name);
 129                free(plat->reg);
 130                return -EINVAL;
 131        }
 132
 133        memcpy(plat->reg, reg_defaults, plat->buf_size);
 134
 135        return 0;
 136}
 137
 138struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = {
 139        .xfer = sandbox_i2c_pmic_xfer,
 140};
 141
 142static const struct udevice_id sandbox_i2c_pmic_ids[] = {
 143        { .compatible = "sandbox,i2c-pmic" },
 144        { }
 145};
 146
 147U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = {
 148        .name           = "sandbox_i2c_pmic_emul",
 149        .id             = UCLASS_I2C_EMUL,
 150        .of_match       = sandbox_i2c_pmic_ids,
 151        .ofdata_to_platdata = sandbox_i2c_pmic_ofdata_to_platdata,
 152        .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_pmic_plat_data),
 153        .ops            = &sandbox_i2c_pmic_emul_ops,
 154};
 155