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