]> Git Repo - J-u-boot.git/blob - drivers/i2c/ihs_i2c.c
net: rswitch: Add PHY C22 access support
[J-u-boot.git] / drivers / i2c / ihs_i2c.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2013
4  * Dirk Eibach,  Guntermann & Drunck GmbH, [email protected]
5  */
6
7 #include <i2c.h>
8 #include <dm.h>
9 #include <regmap.h>
10 #include <log.h>
11 #include <asm/global_data.h>
12 #include <asm/unaligned.h>
13 #include <linux/bitops.h>
14 #include <linux/delay.h>
15
16 struct ihs_i2c_priv {
17         uint speed;
18         struct regmap *map;
19 };
20
21 struct ihs_i2c_regs {
22         u16 interrupt_status;
23         u16 interrupt_enable_control;
24         u16 write_mailbox_ext;
25         u16 write_mailbox;
26         u16 read_mailbox_ext;
27         u16 read_mailbox;
28 };
29
30 #define ihs_i2c_set(map, member, val) \
31         regmap_set(map, struct ihs_i2c_regs, member, val)
32
33 #define ihs_i2c_get(map, member, valp) \
34         regmap_get(map, struct ihs_i2c_regs, member, valp)
35
36 enum {
37         I2CINT_ERROR_EV = BIT(13),
38         I2CINT_TRANSMIT_EV = BIT(14),
39         I2CINT_RECEIVE_EV = BIT(15),
40 };
41
42 enum {
43         I2CMB_READ = 0 << 10,
44         I2CMB_WRITE = 1 << 10,
45         I2CMB_1BYTE = 0 << 11,
46         I2CMB_2BYTE = 1 << 11,
47         I2CMB_DONT_HOLD_BUS = 0 << 13,
48         I2CMB_HOLD_BUS = 1 << 13,
49         I2CMB_NATIVE = 2 << 14,
50 };
51
52 enum {
53         I2COP_WRITE = 0,
54         I2COP_READ = 1,
55 };
56
57 static int wait_for_int(struct udevice *dev, int read)
58 {
59         u16 val;
60         uint ctr = 0;
61         struct ihs_i2c_priv *priv = dev_get_priv(dev);
62
63         ihs_i2c_get(priv->map, interrupt_status, &val);
64         /* Wait until error or receive/transmit interrupt was raised */
65         while (!(val & (I2CINT_ERROR_EV
66                | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
67                 udelay(10);
68                 if (ctr++ > 5000) {
69                         debug("%s: timed out\n", __func__);
70                         return -ETIMEDOUT;
71                 }
72                 ihs_i2c_get(priv->map, interrupt_status, &val);
73         }
74
75         return (val & I2CINT_ERROR_EV) ? -EIO : 0;
76 }
77
78 static int ihs_i2c_transfer(struct udevice *dev, uchar chip,
79                             uchar *buffer, int len, int read, bool is_last)
80 {
81         u16 val;
82         u16 data;
83         int res;
84         struct ihs_i2c_priv *priv = dev_get_priv(dev);
85
86         /* Clear interrupt status */
87         data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
88         ihs_i2c_set(priv->map, interrupt_status, data);
89         ihs_i2c_get(priv->map, interrupt_status, &val);
90
91         /* If we want to write and have data, write the bytes to the mailbox */
92         if (!read && len) {
93                 val = buffer[0];
94
95                 if (len > 1)
96                         val |= buffer[1] << 8;
97                 ihs_i2c_set(priv->map, write_mailbox_ext, val);
98         }
99
100         data = I2CMB_NATIVE
101                | (read ? 0 : I2CMB_WRITE)
102                | (chip << 1)
103                | ((len > 1) ? I2CMB_2BYTE : 0)
104                | (is_last ? 0 : I2CMB_HOLD_BUS);
105
106         ihs_i2c_set(priv->map, write_mailbox, data);
107
108         res = wait_for_int(dev, read);
109         if (res) {
110                 if (res == -ETIMEDOUT)
111                         debug("%s: time out while waiting for event\n", __func__);
112
113                 return res;
114         }
115
116         /* If we want to read, get the bytes from the mailbox */
117         if (read) {
118                 ihs_i2c_get(priv->map, read_mailbox_ext, &val);
119                 buffer[0] = val & 0xff;
120                 if (len > 1)
121                         buffer[1] = val >> 8;
122         }
123
124         return 0;
125 }
126
127 static int ihs_i2c_send_buffer(struct udevice *dev, uchar chip, u8 *data, int len, bool hold_bus, int read)
128 {
129         int res;
130
131         while (len) {
132                 int transfer = min(len, 2);
133                 bool is_last = len <= transfer;
134
135                 res = ihs_i2c_transfer(dev, chip, data, transfer, read,
136                                        hold_bus ? false : is_last);
137                 if (res)
138                         return res;
139
140                 data += transfer;
141                 len -= transfer;
142         }
143
144         return 0;
145 }
146
147 static int ihs_i2c_address(struct udevice *dev, uchar chip, u8 *addr, int alen,
148                            bool hold_bus)
149 {
150         return ihs_i2c_send_buffer(dev, chip, addr, alen, hold_bus, I2COP_WRITE);
151 }
152
153 static int ihs_i2c_access(struct udevice *dev, uchar chip, u8 *addr,
154                           int alen, uchar *buffer, int len, int read)
155 {
156         int res;
157
158         /* Don't hold the bus if length of data to send/receive is zero */
159         if (len <= 0)
160                 return -EINVAL;
161
162         res = ihs_i2c_address(dev, chip, addr, alen, len);
163         if (res)
164                 return res;
165
166         return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read);
167 }
168
169 int ihs_i2c_probe(struct udevice *bus)
170 {
171         struct ihs_i2c_priv *priv = dev_get_priv(bus);
172
173         regmap_init_mem(dev_ofnode(bus), &priv->map);
174
175         return 0;
176 }
177
178 static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed)
179 {
180         struct ihs_i2c_priv *priv = dev_get_priv(bus);
181
182         if (speed != priv->speed && priv->speed != 0)
183                 return -EINVAL;
184
185         priv->speed = speed;
186
187         return 0;
188 }
189
190 static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
191 {
192         struct i2c_msg *dmsg, *omsg, dummy;
193
194         memset(&dummy, 0, sizeof(struct i2c_msg));
195
196         /* We expect either two messages (one with an offset and one with the
197          * actual data) or one message (just data)
198          */
199         if (nmsgs > 2 || nmsgs == 0) {
200                 debug("%s: Only one or two messages are supported\n", __func__);
201                 return -ENOTSUPP;
202         }
203
204         omsg = nmsgs == 1 ? &dummy : msg;
205         dmsg = nmsgs == 1 ? msg : msg + 1;
206
207         if (dmsg->flags & I2C_M_RD)
208                 return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
209                                       omsg->len, dmsg->buf, dmsg->len,
210                                       I2COP_READ);
211         else
212                 return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
213                                       omsg->len, dmsg->buf, dmsg->len,
214                                       I2COP_WRITE);
215 }
216
217 static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
218                               u32 chip_flags)
219 {
220         uchar buffer[2];
221         int res;
222
223         res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true);
224         if (res)
225                 return res;
226
227         return 0;
228 }
229
230 static const struct dm_i2c_ops ihs_i2c_ops = {
231         .xfer           = ihs_i2c_xfer,
232         .probe_chip     = ihs_i2c_probe_chip,
233         .set_bus_speed  = ihs_i2c_set_bus_speed,
234 };
235
236 static const struct udevice_id ihs_i2c_ids[] = {
237         { .compatible = "gdsys,ihs_i2cmaster", },
238         { /* sentinel */ }
239 };
240
241 U_BOOT_DRIVER(i2c_ihs) = {
242         .name = "i2c_ihs",
243         .id = UCLASS_I2C,
244         .of_match = ihs_i2c_ids,
245         .probe = ihs_i2c_probe,
246         .priv_auto      = sizeof(struct ihs_i2c_priv),
247         .ops = &ihs_i2c_ops,
248 };
This page took 0.03953 seconds and 4 git commands to generate.