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; 22 u8 reg[SANDBOX_PMIC_REG_COUNT]; 23 }; 24 25 static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, 26 uchar *buffer, int len) 27 { 28 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 29 30 if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { 31 pr_err("Request exceeds PMIC register range! Max register: %#x", 32 SANDBOX_PMIC_REG_COUNT); 33 return -EFAULT; 34 } 35 36 debug("Read PMIC: %#x at register: %#x count: %d\n", 37 (unsigned)chip & 0xff, plat->rw_reg, len); 38 39 memcpy(buffer, &plat->reg[plat->rw_reg], len); 40 41 return 0; 42 } 43 44 static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, 45 uchar *buffer, int len, 46 bool next_is_read) 47 { 48 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 49 50 /* Probe only */ 51 if (!len) 52 return 0; 53 54 /* Set PMIC register for I/O */ 55 plat->rw_reg = *buffer; 56 57 debug("Write PMIC: %#x at register: %#x count: %d\n", 58 (unsigned)chip & 0xff, plat->rw_reg, len); 59 60 /* For read operation, set (write) only chip reg */ 61 if (next_is_read) 62 return 0; 63 64 buffer++; 65 len--; 66 67 if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { 68 pr_err("Request exceeds PMIC register range! Max register: %#x", 69 SANDBOX_PMIC_REG_COUNT); 70 } 71 72 memcpy(&plat->reg[plat->rw_reg], buffer, len); 73 74 return 0; 75 } 76 77 static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg, 78 int nmsgs) 79 { 80 int ret = 0; 81 82 for (; nmsgs > 0; nmsgs--, msg++) { 83 bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); 84 if (msg->flags & I2C_M_RD) { 85 ret = sandbox_i2c_pmic_read_data(emul, msg->addr, 86 msg->buf, msg->len); 87 } else { 88 ret = sandbox_i2c_pmic_write_data(emul, msg->addr, 89 msg->buf, msg->len, 90 next_is_read); 91 } 92 93 if (ret) 94 break; 95 } 96 97 return ret; 98 } 99 100 static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul) 101 { 102 struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); 103 const u8 *reg_defaults; 104 105 debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__); 106 107 reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults", 108 SANDBOX_PMIC_REG_COUNT); 109 110 if (!reg_defaults) { 111 pr_err("Property \"reg-defaults\" not found for device: %s!", 112 emul->name); 113 return -EINVAL; 114 } 115 116 memcpy(&plat->reg, reg_defaults, SANDBOX_PMIC_REG_COUNT); 117 118 return 0; 119 } 120 121 struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { 122 .xfer = sandbox_i2c_pmic_xfer, 123 }; 124 125 static const struct udevice_id sandbox_i2c_pmic_ids[] = { 126 { .compatible = "sandbox,i2c-pmic" }, 127 { } 128 }; 129 130 U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = { 131 .name = "sandbox_i2c_pmic_emul", 132 .id = UCLASS_I2C_EMUL, 133 .of_match = sandbox_i2c_pmic_ids, 134 .ofdata_to_platdata = sandbox_i2c_pmic_ofdata_to_platdata, 135 .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_pmic_plat_data), 136 .ops = &sandbox_i2c_pmic_emul_ops, 137 }; 138