1 /* 2 * Copyright (C) 2015 Samsung Electronics 3 * Przemyslaw Marczak <p.marczak@samsung.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <fdtdec.h> 10 #include <errno.h> 11 #include <dm.h> 12 #include <i2c.h> 13 #include <power/pmic.h> 14 #include <power/sandbox_pmic.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 /** 19 * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC 20 * 21 * @rw_reg: PMICs register of the chip I/O transaction 22 * @reg: PMICs registers array 23 */ 24 struct sandbox_i2c_pmic_plat_data { 25 u8 rw_reg; 26 u8 reg[SANDBOX_PMIC_REG_COUNT]; 27 }; 28 29 static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, 30 uchar *buffer, int len) 31 { 32 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 33 34 if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { 35 error("Request exceeds PMIC register range! Max register: %#x", 36 SANDBOX_PMIC_REG_COUNT); 37 return -EFAULT; 38 } 39 40 debug("Read PMIC: %#x at register: %#x count: %d\n", 41 (unsigned)chip & 0xff, plat->rw_reg, len); 42 43 memcpy(buffer, &plat->reg[plat->rw_reg], len); 44 45 return 0; 46 } 47 48 static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, 49 uchar *buffer, int len, 50 bool next_is_read) 51 { 52 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 53 54 /* Probe only */ 55 if (!len) 56 return 0; 57 58 /* Set PMIC register for I/O */ 59 plat->rw_reg = *buffer; 60 61 debug("Write PMIC: %#x at register: %#x count: %d\n", 62 (unsigned)chip & 0xff, plat->rw_reg, 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_reg + len > SANDBOX_PMIC_REG_COUNT) { 72 error("Request exceeds PMIC register range! Max register: %#x", 73 SANDBOX_PMIC_REG_COUNT); 74 } 75 76 memcpy(&plat->reg[plat->rw_reg], 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 const u8 *reg_defaults; 108 109 debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__); 110 111 reg_defaults = fdtdec_locate_byte_array(gd->fdt_blob, emul->of_offset, 112 "reg-defaults", 113 SANDBOX_PMIC_REG_COUNT); 114 115 if (!reg_defaults) { 116 error("Property \"reg-defaults\" not found for device: %s!", 117 emul->name); 118 return -EINVAL; 119 } 120 121 memcpy(&plat->reg, reg_defaults, SANDBOX_PMIC_REG_COUNT); 122 123 return 0; 124 } 125 126 struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { 127 .xfer = sandbox_i2c_pmic_xfer, 128 }; 129 130 static const struct udevice_id sandbox_i2c_pmic_ids[] = { 131 { .compatible = "sandbox,i2c-pmic" }, 132 { } 133 }; 134 135 U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = { 136 .name = "sandbox_i2c_pmic_emul", 137 .id = UCLASS_I2C_EMUL, 138 .of_match = sandbox_i2c_pmic_ids, 139 .ofdata_to_platdata = sandbox_i2c_pmic_ofdata_to_platdata, 140 .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_pmic_plat_data), 141 .ops = &sandbox_i2c_pmic_emul_ops, 142 }; 143