xref: /openbmc/u-boot/drivers/power/pmic/i2c_pmic_emul.c (revision d024236e5a31a2b4b82cbcc98b31b8170fc88d28)
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