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