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 */ 20 struct 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 28 static 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 47 static 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 81 static 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 104 static 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 138 struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { 139 .xfer = sandbox_i2c_pmic_xfer, 140 }; 141 142 static const struct udevice_id sandbox_i2c_pmic_ids[] = { 143 { .compatible = "sandbox,i2c-pmic" }, 144 { } 145 }; 146 147 U_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