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,
112 			dev_of_offset(emul), "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