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 <errno.h> 10 #include <dm.h> 11 #include <i2c.h> 12 #include <power/pmic.h> 13 #include <power/sandbox_pmic.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 /** 18 * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC 19 * 20 * @rw_reg: PMICs register of the chip I/O transaction 21 * @reg: PMICs registers array 22 */ 23 struct sandbox_i2c_pmic_plat_data { 24 u8 rw_reg; 25 u8 reg[SANDBOX_PMIC_REG_COUNT]; 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_reg + len > SANDBOX_PMIC_REG_COUNT) { 34 error("Request exceeds PMIC register range! Max register: %#x", 35 SANDBOX_PMIC_REG_COUNT); 36 return -EFAULT; 37 } 38 39 debug("Read PMIC: %#x at register: %#x count: %d\n", 40 (unsigned)chip & 0xff, plat->rw_reg, len); 41 42 memcpy(buffer, &plat->reg[plat->rw_reg], 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 60 debug("Write PMIC: %#x at register: %#x count: %d\n", 61 (unsigned)chip & 0xff, plat->rw_reg, len); 62 63 /* For read operation, set (write) only chip reg */ 64 if (next_is_read) 65 return 0; 66 67 buffer++; 68 len--; 69 70 if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { 71 error("Request exceeds PMIC register range! Max register: %#x", 72 SANDBOX_PMIC_REG_COUNT); 73 } 74 75 memcpy(&plat->reg[plat->rw_reg], buffer, len); 76 77 return 0; 78 } 79 80 static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg, 81 int nmsgs) 82 { 83 int ret = 0; 84 85 for (; nmsgs > 0; nmsgs--, msg++) { 86 bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); 87 if (msg->flags & I2C_M_RD) { 88 ret = sandbox_i2c_pmic_read_data(emul, msg->addr, 89 msg->buf, msg->len); 90 } else { 91 ret = sandbox_i2c_pmic_write_data(emul, msg->addr, 92 msg->buf, msg->len, 93 next_is_read); 94 } 95 96 if (ret) 97 break; 98 } 99 100 return ret; 101 } 102 103 static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul) 104 { 105 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 106 const u8 *reg_defaults; 107 108 debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__); 109 110 reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults", 111 SANDBOX_PMIC_REG_COUNT); 112 113 if (!reg_defaults) { 114 error("Property \"reg-defaults\" not found for device: %s!", 115 emul->name); 116 return -EINVAL; 117 } 118 119 memcpy(&plat->reg, reg_defaults, SANDBOX_PMIC_REG_COUNT); 120 121 return 0; 122 } 123 124 struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { 125 .xfer = sandbox_i2c_pmic_xfer, 126 }; 127 128 static const struct udevice_id sandbox_i2c_pmic_ids[] = { 129 { .compatible = "sandbox,i2c-pmic" }, 130 { } 131 }; 132 133 U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = { 134 .name = "sandbox_i2c_pmic_emul", 135 .id = UCLASS_I2C_EMUL, 136 .of_match = sandbox_i2c_pmic_ids, 137 .ofdata_to_platdata = sandbox_i2c_pmic_ofdata_to_platdata, 138 .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_pmic_plat_data), 139 .ops = &sandbox_i2c_pmic_emul_ops, 140 }; 141