Merge git://git.denx.de/u-boot-sunxi
[oweals/u-boot.git] / drivers / power / pmic / i2c_pmic_emul.c
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 };