blob: 02f0144930cca55a86a353082441fe0894497f38 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Eibachb9577432014-07-03 09:28:18 +02002/*
3 * (C) Copyright 2013
Mario Sixb4893582018-03-06 08:04:58 +01004 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
Dirk Eibachb9577432014-07-03 09:28:18 +02005 */
6
7#include <common.h>
8#include <i2c.h>
Igor Opaniukf7c91762021-02-09 13:52:45 +02009#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +010010#include <dm.h>
Mario Six67b845b2019-01-28 09:45:57 +010011#include <regmap.h>
Mario Six3bb409c2018-01-15 11:08:11 +010012#else
Dirk Eibachb9577432014-07-03 09:28:18 +020013#include <gdsys_fpga.h>
Mario Six3bb409c2018-01-15 11:08:11 +010014#endif
Simon Glass0f2af882020-05-10 11:40:05 -060015#include <log.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060016#include <asm/global_data.h>
Mario Six48689b42018-01-15 11:08:10 +010017#include <asm/unaligned.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060018#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060019#include <linux/delay.h>
Dirk Eibachb9577432014-07-03 09:28:18 +020020
Igor Opaniukf7c91762021-02-09 13:52:45 +020021#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +010022struct ihs_i2c_priv {
23 uint speed;
Mario Six67b845b2019-01-28 09:45:57 +010024 struct regmap *map;
Mario Six3bb409c2018-01-15 11:08:11 +010025};
26
Mario Six67b845b2019-01-28 09:45:57 +010027struct ihs_i2c_regs {
28 u16 interrupt_status;
29 u16 interrupt_enable_control;
30 u16 write_mailbox_ext;
31 u16 write_mailbox;
32 u16 read_mailbox_ext;
33 u16 read_mailbox;
Mario Six3bb409c2018-01-15 11:08:11 +010034};
35
Mario Six67b845b2019-01-28 09:45:57 +010036#define ihs_i2c_set(map, member, val) \
37 regmap_set(map, struct ihs_i2c_regs, member, val)
38
39#define ihs_i2c_get(map, member, valp) \
40 regmap_get(map, struct ihs_i2c_regs, member, valp)
41
Mario Six3bb409c2018-01-15 11:08:11 +010042#else /* !CONFIG_DM_I2C */
Dirk Eibachb9577432014-07-03 09:28:18 +020043DECLARE_GLOBAL_DATA_PTR;
44
Dirk Eibach9ac33852015-10-28 11:46:22 +010045#ifdef CONFIG_SYS_I2C_IHS_DUAL
Mario Six3bb409c2018-01-15 11:08:11 +010046
Dirk Eibach9ac33852015-10-28 11:46:22 +010047#define I2C_SET_REG(fld, val) \
Dirk Eibach2c7212b2015-10-28 11:46:23 +010048 do { \
49 if (I2C_ADAP_HWNR & 0x10) \
50 FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
51 else \
52 FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
53 } while (0)
Dirk Eibach9ac33852015-10-28 11:46:22 +010054#else
55#define I2C_SET_REG(fld, val) \
Dirk Eibach2c7212b2015-10-28 11:46:23 +010056 FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
Dirk Eibach9ac33852015-10-28 11:46:22 +010057#endif
58
59#ifdef CONFIG_SYS_I2C_IHS_DUAL
60#define I2C_GET_REG(fld, val) \
Dirk Eibach2c7212b2015-10-28 11:46:23 +010061 do { \
62 if (I2C_ADAP_HWNR & 0x10) \
63 FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
64 else \
65 FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
66 } while (0)
Dirk Eibach9ac33852015-10-28 11:46:22 +010067#else
68#define I2C_GET_REG(fld, val) \
Dirk Eibach2c7212b2015-10-28 11:46:23 +010069 FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
Dirk Eibach9ac33852015-10-28 11:46:22 +010070#endif
Mario Six3bb409c2018-01-15 11:08:11 +010071#endif /* CONFIG_DM_I2C */
Dirk Eibach9ac33852015-10-28 11:46:22 +010072
Dirk Eibachb9577432014-07-03 09:28:18 +020073enum {
Mario Six48689b42018-01-15 11:08:10 +010074 I2CINT_ERROR_EV = BIT(13),
75 I2CINT_TRANSMIT_EV = BIT(14),
76 I2CINT_RECEIVE_EV = BIT(15),
Dirk Eibachb9577432014-07-03 09:28:18 +020077};
78
79enum {
Mario Six48689b42018-01-15 11:08:10 +010080 I2CMB_READ = 0 << 10,
Dirk Eibachb9577432014-07-03 09:28:18 +020081 I2CMB_WRITE = 1 << 10,
Mario Six48689b42018-01-15 11:08:10 +010082 I2CMB_1BYTE = 0 << 11,
Dirk Eibachb9577432014-07-03 09:28:18 +020083 I2CMB_2BYTE = 1 << 11,
Mario Six48689b42018-01-15 11:08:10 +010084 I2CMB_DONT_HOLD_BUS = 0 << 13,
Dirk Eibachb9577432014-07-03 09:28:18 +020085 I2CMB_HOLD_BUS = 1 << 13,
86 I2CMB_NATIVE = 2 << 14,
87};
88
Mario Six48689b42018-01-15 11:08:10 +010089enum {
90 I2COP_WRITE = 0,
91 I2COP_READ = 1,
92};
93
Igor Opaniukf7c91762021-02-09 13:52:45 +020094#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +010095static int wait_for_int(struct udevice *dev, int read)
96#else
Dirk Eibachb9577432014-07-03 09:28:18 +020097static int wait_for_int(bool read)
Mario Six3bb409c2018-01-15 11:08:11 +010098#endif
Dirk Eibachb9577432014-07-03 09:28:18 +020099{
100 u16 val;
Mario Six48689b42018-01-15 11:08:10 +0100101 uint ctr = 0;
Igor Opaniukf7c91762021-02-09 13:52:45 +0200102#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +0100103 struct ihs_i2c_priv *priv = dev_get_priv(dev);
Mario Six3bb409c2018-01-15 11:08:11 +0100104#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200105
Igor Opaniukf7c91762021-02-09 13:52:45 +0200106#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100107 ihs_i2c_get(priv->map, interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100108#else
Dirk Eibach9ac33852015-10-28 11:46:22 +0100109 I2C_GET_REG(interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100110#endif
Mario Six48689b42018-01-15 11:08:10 +0100111 /* Wait until error or receive/transmit interrupt was raised */
Dirk Eibachb9577432014-07-03 09:28:18 +0200112 while (!(val & (I2CINT_ERROR_EV
113 | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
114 udelay(10);
Mario Six5525d072019-01-28 09:45:58 +0100115 if (ctr++ > 5000) {
116 debug("%s: timed out\n", __func__);
117 return -ETIMEDOUT;
118 }
Igor Opaniukf7c91762021-02-09 13:52:45 +0200119#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100120 ihs_i2c_get(priv->map, interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100121#else
Dirk Eibach9ac33852015-10-28 11:46:22 +0100122 I2C_GET_REG(interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100123#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200124 }
125
Mario Six5525d072019-01-28 09:45:58 +0100126 return (val & I2CINT_ERROR_EV) ? -EIO : 0;
Dirk Eibachb9577432014-07-03 09:28:18 +0200127}
128
Igor Opaniukf7c91762021-02-09 13:52:45 +0200129#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +0100130static int ihs_i2c_transfer(struct udevice *dev, uchar chip,
131 uchar *buffer, int len, int read, bool is_last)
132#else
Dirk Eibachb9577432014-07-03 09:28:18 +0200133static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
134 bool is_last)
Mario Six3bb409c2018-01-15 11:08:11 +0100135#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200136{
137 u16 val;
Mario Six4d90d9d2018-03-28 14:37:42 +0200138 u16 data;
Mario Six5525d072019-01-28 09:45:58 +0100139 int res;
Igor Opaniukf7c91762021-02-09 13:52:45 +0200140#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +0100141 struct ihs_i2c_priv *priv = dev_get_priv(dev);
Mario Six3bb409c2018-01-15 11:08:11 +0100142#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200143
Mario Six48689b42018-01-15 11:08:10 +0100144 /* Clear interrupt status */
Mario Six4d90d9d2018-03-28 14:37:42 +0200145 data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
Igor Opaniukf7c91762021-02-09 13:52:45 +0200146#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100147 ihs_i2c_set(priv->map, interrupt_status, data);
148 ihs_i2c_get(priv->map, interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100149#else
Mario Six4d90d9d2018-03-28 14:37:42 +0200150 I2C_SET_REG(interrupt_status, data);
Dirk Eibach9ac33852015-10-28 11:46:22 +0100151 I2C_GET_REG(interrupt_status, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100152#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200153
Mario Six48689b42018-01-15 11:08:10 +0100154 /* If we want to write and have data, write the bytes to the mailbox */
Dirk Eibachb9577432014-07-03 09:28:18 +0200155 if (!read && len) {
156 val = buffer[0];
157
158 if (len > 1)
159 val |= buffer[1] << 8;
Igor Opaniukf7c91762021-02-09 13:52:45 +0200160#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100161 ihs_i2c_set(priv->map, write_mailbox_ext, val);
Mario Six3bb409c2018-01-15 11:08:11 +0100162#else
Dirk Eibach9ac33852015-10-28 11:46:22 +0100163 I2C_SET_REG(write_mailbox_ext, val);
Mario Six3bb409c2018-01-15 11:08:11 +0100164#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200165 }
166
Mario Six4d90d9d2018-03-28 14:37:42 +0200167 data = I2CMB_NATIVE
168 | (read ? 0 : I2CMB_WRITE)
169 | (chip << 1)
170 | ((len > 1) ? I2CMB_2BYTE : 0)
171 | (is_last ? 0 : I2CMB_HOLD_BUS);
172
Igor Opaniukf7c91762021-02-09 13:52:45 +0200173#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100174 ihs_i2c_set(priv->map, write_mailbox, data);
Mario Six3bb409c2018-01-15 11:08:11 +0100175#else
Mario Six4d90d9d2018-03-28 14:37:42 +0200176 I2C_SET_REG(write_mailbox, data);
Mario Six3bb409c2018-01-15 11:08:11 +0100177#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200178
Igor Opaniukf7c91762021-02-09 13:52:45 +0200179#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six5525d072019-01-28 09:45:58 +0100180 res = wait_for_int(dev, read);
Mario Six3bb409c2018-01-15 11:08:11 +0100181#else
Mario Six5525d072019-01-28 09:45:58 +0100182 res = wait_for_int(read);
Mario Six3bb409c2018-01-15 11:08:11 +0100183#endif
Mario Six5525d072019-01-28 09:45:58 +0100184 if (res) {
185 if (res == -ETIMEDOUT)
186 debug("%s: time out while waiting for event\n", __func__);
187
188 return res;
189 }
Dirk Eibachb9577432014-07-03 09:28:18 +0200190
Mario Six48689b42018-01-15 11:08:10 +0100191 /* If we want to read, get the bytes from the mailbox */
Dirk Eibachb9577432014-07-03 09:28:18 +0200192 if (read) {
Igor Opaniukf7c91762021-02-09 13:52:45 +0200193#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six67b845b2019-01-28 09:45:57 +0100194 ihs_i2c_get(priv->map, read_mailbox_ext, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100195#else
Dirk Eibach9ac33852015-10-28 11:46:22 +0100196 I2C_GET_REG(read_mailbox_ext, &val);
Mario Six3bb409c2018-01-15 11:08:11 +0100197#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200198 buffer[0] = val & 0xff;
199 if (len > 1)
200 buffer[1] = val >> 8;
201 }
202
203 return 0;
204}
205
Igor Opaniukf7c91762021-02-09 13:52:45 +0200206#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six96961e82018-01-15 11:08:12 +0100207static int ihs_i2c_send_buffer(struct udevice *dev, uchar chip, u8 *data, int len, bool hold_bus, int read)
Mario Six3bb409c2018-01-15 11:08:11 +0100208#else
Mario Six96961e82018-01-15 11:08:12 +0100209static int ihs_i2c_send_buffer(uchar chip, u8 *data, int len, bool hold_bus,
210 int read)
Mario Six3bb409c2018-01-15 11:08:11 +0100211#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200212{
Mario Six5525d072019-01-28 09:45:58 +0100213 int res;
214
Mario Six96961e82018-01-15 11:08:12 +0100215 while (len) {
216 int transfer = min(len, 2);
217 bool is_last = len <= transfer;
Dirk Eibachb9577432014-07-03 09:28:18 +0200218
Igor Opaniukf7c91762021-02-09 13:52:45 +0200219#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six5525d072019-01-28 09:45:58 +0100220 res = ihs_i2c_transfer(dev, chip, data, transfer, read,
221 hold_bus ? false : is_last);
Mario Six3bb409c2018-01-15 11:08:11 +0100222#else
Mario Six5525d072019-01-28 09:45:58 +0100223 res = ihs_i2c_transfer(chip, data, transfer, read,
224 hold_bus ? false : is_last);
Mario Six3bb409c2018-01-15 11:08:11 +0100225#endif
Mario Six5525d072019-01-28 09:45:58 +0100226 if (res)
227 return res;
Dirk Eibachb9577432014-07-03 09:28:18 +0200228
Mario Six96961e82018-01-15 11:08:12 +0100229 data += transfer;
230 len -= transfer;
Dirk Eibachb9577432014-07-03 09:28:18 +0200231 }
232
233 return 0;
234}
235
Igor Opaniukf7c91762021-02-09 13:52:45 +0200236#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six96961e82018-01-15 11:08:12 +0100237static int ihs_i2c_address(struct udevice *dev, uchar chip, u8 *addr, int alen,
238 bool hold_bus)
239#else
240static int ihs_i2c_address(uchar chip, u8 *addr, int alen, bool hold_bus)
241#endif
242{
Igor Opaniukf7c91762021-02-09 13:52:45 +0200243#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six96961e82018-01-15 11:08:12 +0100244 return ihs_i2c_send_buffer(dev, chip, addr, alen, hold_bus, I2COP_WRITE);
245#else
246 return ihs_i2c_send_buffer(chip, addr, alen, hold_bus, I2COP_WRITE);
247#endif
248}
249
Igor Opaniukf7c91762021-02-09 13:52:45 +0200250#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +0100251static int ihs_i2c_access(struct udevice *dev, uchar chip, u8 *addr,
252 int alen, uchar *buffer, int len, int read)
253#else
Mario Six48689b42018-01-15 11:08:10 +0100254static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, u8 *addr,
255 int alen, uchar *buffer, int len, int read)
Mario Six3bb409c2018-01-15 11:08:11 +0100256#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200257{
Mario Six5525d072019-01-28 09:45:58 +0100258 int res;
259
Mario Six48689b42018-01-15 11:08:10 +0100260 /* Don't hold the bus if length of data to send/receive is zero */
Mario Six5525d072019-01-28 09:45:58 +0100261 if (len <= 0)
262 return -EINVAL;
263
Igor Opaniukf7c91762021-02-09 13:52:45 +0200264#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six5525d072019-01-28 09:45:58 +0100265 res = ihs_i2c_address(dev, chip, addr, alen, len);
Mario Six3bb409c2018-01-15 11:08:11 +0100266#else
Mario Six5525d072019-01-28 09:45:58 +0100267 res = ihs_i2c_address(chip, addr, alen, len);
Mario Six3bb409c2018-01-15 11:08:11 +0100268#endif
Mario Six5525d072019-01-28 09:45:58 +0100269 if (res)
270 return res;
Dirk Eibachb9577432014-07-03 09:28:18 +0200271
Igor Opaniukf7c91762021-02-09 13:52:45 +0200272#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six96961e82018-01-15 11:08:12 +0100273 return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read);
Mario Six3bb409c2018-01-15 11:08:11 +0100274#else
Mario Six96961e82018-01-15 11:08:12 +0100275 return ihs_i2c_send_buffer(chip, buffer, len, false, read);
Mario Six3bb409c2018-01-15 11:08:11 +0100276#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200277}
278
Igor Opaniukf7c91762021-02-09 13:52:45 +0200279#if CONFIG_IS_ENABLED(DM_I2C)
Mario Six3bb409c2018-01-15 11:08:11 +0100280
281int ihs_i2c_probe(struct udevice *bus)
282{
283 struct ihs_i2c_priv *priv = dev_get_priv(bus);
Mario Six3bb409c2018-01-15 11:08:11 +0100284
Mario Six67b845b2019-01-28 09:45:57 +0100285 regmap_init_mem(dev_ofnode(bus), &priv->map);
Mario Six3bb409c2018-01-15 11:08:11 +0100286
287 return 0;
288}
289
290static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed)
291{
292 struct ihs_i2c_priv *priv = dev_get_priv(bus);
293
294 if (speed != priv->speed && priv->speed != 0)
Mario Six5525d072019-01-28 09:45:58 +0100295 return -EINVAL;
Mario Six3bb409c2018-01-15 11:08:11 +0100296
297 priv->speed = speed;
298
299 return 0;
300}
301
302static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
303{
304 struct i2c_msg *dmsg, *omsg, dummy;
305
306 memset(&dummy, 0, sizeof(struct i2c_msg));
307
308 /* We expect either two messages (one with an offset and one with the
309 * actucal data) or one message (just data)
310 */
311 if (nmsgs > 2 || nmsgs == 0) {
Mario Six5525d072019-01-28 09:45:58 +0100312 debug("%s: Only one or two messages are supported\n", __func__);
313 return -ENOTSUPP;
Mario Six3bb409c2018-01-15 11:08:11 +0100314 }
315
316 omsg = nmsgs == 1 ? &dummy : msg;
317 dmsg = nmsgs == 1 ? msg : msg + 1;
318
319 if (dmsg->flags & I2C_M_RD)
320 return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
321 omsg->len, dmsg->buf, dmsg->len,
322 I2COP_READ);
323 else
324 return ihs_i2c_access(bus, dmsg->addr, omsg->buf,
325 omsg->len, dmsg->buf, dmsg->len,
326 I2COP_WRITE);
327}
328
329static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
330 u32 chip_flags)
331{
332 uchar buffer[2];
Mario Six5525d072019-01-28 09:45:58 +0100333 int res;
Mario Six3bb409c2018-01-15 11:08:11 +0100334
Mario Six5525d072019-01-28 09:45:58 +0100335 res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true);
336 if (res)
337 return res;
Mario Six3bb409c2018-01-15 11:08:11 +0100338
339 return 0;
340}
341
342static const struct dm_i2c_ops ihs_i2c_ops = {
343 .xfer = ihs_i2c_xfer,
344 .probe_chip = ihs_i2c_probe_chip,
345 .set_bus_speed = ihs_i2c_set_bus_speed,
346};
347
348static const struct udevice_id ihs_i2c_ids[] = {
349 { .compatible = "gdsys,ihs_i2cmaster", },
350 { /* sentinel */ }
351};
352
353U_BOOT_DRIVER(i2c_ihs) = {
354 .name = "i2c_ihs",
355 .id = UCLASS_I2C,
356 .of_match = ihs_i2c_ids,
357 .probe = ihs_i2c_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700358 .priv_auto = sizeof(struct ihs_i2c_priv),
Mario Six3bb409c2018-01-15 11:08:11 +0100359 .ops = &ihs_i2c_ops,
360};
361
362#else /* CONFIG_DM_I2C */
363
Dirk Eibachb9577432014-07-03 09:28:18 +0200364static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
365{
366#ifdef CONFIG_SYS_I2C_INIT_BOARD
367 /*
368 * Call board specific i2c bus reset routine before accessing the
369 * environment, which might be in a chip on that bus. For details
370 * about this problem see doc/I2C_Edge_Conditions.
371 */
372 i2c_init_board();
373#endif
374}
375
376static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
377{
378 uchar buffer[2];
Mario Six5525d072019-01-28 09:45:58 +0100379 int res;
Dirk Eibachb9577432014-07-03 09:28:18 +0200380
Mario Six5525d072019-01-28 09:45:58 +0100381 res = ihs_i2c_transfer(chip, buffer, 0, I2COP_READ, true);
382 if (res)
383 return res;
Dirk Eibachb9577432014-07-03 09:28:18 +0200384
385 return 0;
386}
387
388static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
389 int alen, uchar *buffer, int len)
390{
Mario Six48689b42018-01-15 11:08:10 +0100391 u8 addr_bytes[4];
392
393 put_unaligned_le32(addr, addr_bytes);
394
395 return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
396 I2COP_READ);
Dirk Eibachb9577432014-07-03 09:28:18 +0200397}
398
399static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
400 int alen, uchar *buffer, int len)
401{
Mario Six48689b42018-01-15 11:08:10 +0100402 u8 addr_bytes[4];
403
404 put_unaligned_le32(addr, addr_bytes);
405
406 return ihs_i2c_access(adap, chip, addr_bytes, alen, buffer, len,
407 I2COP_WRITE);
Dirk Eibachb9577432014-07-03 09:28:18 +0200408}
409
410static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
Dirk Eibach9ac33852015-10-28 11:46:22 +0100411 unsigned int speed)
Dirk Eibachb9577432014-07-03 09:28:18 +0200412{
413 if (speed != adap->speed)
Mario Six5525d072019-01-28 09:45:58 +0100414 return -EINVAL;
Dirk Eibachb9577432014-07-03 09:28:18 +0200415 return speed;
416}
417
418/*
419 * Register IHS i2c adapters
420 */
421#ifdef CONFIG_SYS_I2C_IHS_CH0
422U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
423 ihs_i2c_read, ihs_i2c_write,
424 ihs_i2c_set_bus_speed,
425 CONFIG_SYS_I2C_IHS_SPEED_0,
426 CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
Dirk Eibach9ac33852015-10-28 11:46:22 +0100427#ifdef CONFIG_SYS_I2C_IHS_DUAL
428U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
429 ihs_i2c_read, ihs_i2c_write,
430 ihs_i2c_set_bus_speed,
431 CONFIG_SYS_I2C_IHS_SPEED_0_1,
432 CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
433#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200434#endif
435#ifdef CONFIG_SYS_I2C_IHS_CH1
436U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
437 ihs_i2c_read, ihs_i2c_write,
438 ihs_i2c_set_bus_speed,
439 CONFIG_SYS_I2C_IHS_SPEED_1,
440 CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
Dirk Eibach9ac33852015-10-28 11:46:22 +0100441#ifdef CONFIG_SYS_I2C_IHS_DUAL
442U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
443 ihs_i2c_read, ihs_i2c_write,
444 ihs_i2c_set_bus_speed,
445 CONFIG_SYS_I2C_IHS_SPEED_1_1,
446 CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
447#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200448#endif
449#ifdef CONFIG_SYS_I2C_IHS_CH2
450U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
451 ihs_i2c_read, ihs_i2c_write,
452 ihs_i2c_set_bus_speed,
453 CONFIG_SYS_I2C_IHS_SPEED_2,
454 CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
Dirk Eibach9ac33852015-10-28 11:46:22 +0100455#ifdef CONFIG_SYS_I2C_IHS_DUAL
456U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
457 ihs_i2c_read, ihs_i2c_write,
458 ihs_i2c_set_bus_speed,
459 CONFIG_SYS_I2C_IHS_SPEED_2_1,
460 CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
461#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200462#endif
463#ifdef CONFIG_SYS_I2C_IHS_CH3
464U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
465 ihs_i2c_read, ihs_i2c_write,
466 ihs_i2c_set_bus_speed,
467 CONFIG_SYS_I2C_IHS_SPEED_3,
468 CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
Dirk Eibach9ac33852015-10-28 11:46:22 +0100469#ifdef CONFIG_SYS_I2C_IHS_DUAL
470U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
471 ihs_i2c_read, ihs_i2c_write,
472 ihs_i2c_set_bus_speed,
473 CONFIG_SYS_I2C_IHS_SPEED_3_1,
474 CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
475#endif
Dirk Eibachb9577432014-07-03 09:28:18 +0200476#endif
Mario Six3bb409c2018-01-15 11:08:11 +0100477#endif /* CONFIG_DM_I2C */