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