101ec99d9SAlbert Aribaud /*
2306563a7SAlbert Aribaud * Driver for the TWSI (i2c) controller found on the Marvell
3306563a7SAlbert Aribaud * orion5x and kirkwood SoC families.
401ec99d9SAlbert Aribaud *
557b4bce9SAlbert ARIBAUD * Author: Albert Aribaud <albert.u.boot@aribaud.net>
6306563a7SAlbert Aribaud * Copyright (c) 2010 Albert Aribaud.
701ec99d9SAlbert Aribaud *
81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
901ec99d9SAlbert Aribaud */
10306563a7SAlbert Aribaud
1101ec99d9SAlbert Aribaud #include <common.h>
1201ec99d9SAlbert Aribaud #include <i2c.h>
131221ce45SMasahiro Yamada #include <linux/errno.h>
1401ec99d9SAlbert Aribaud #include <asm/io.h>
15c68c6243Smario.six@gdsys.cc #include <linux/compat.h>
1614a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
1714a6ff2cSmario.six@gdsys.cc #include <dm.h>
1814a6ff2cSmario.six@gdsys.cc #endif
1914a6ff2cSmario.six@gdsys.cc
2014a6ff2cSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR;
2101ec99d9SAlbert Aribaud
22306563a7SAlbert Aribaud /*
2349c801bfSmario.six@gdsys.cc * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
2449c801bfSmario.six@gdsys.cc * settings
25306563a7SAlbert Aribaud */
2601ec99d9SAlbert Aribaud
2714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
28306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X)
29306563a7SAlbert Aribaud #include <asm/arch/orion5x.h>
3081e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
313dc23f78SStefan Roese #include <asm/arch/soc.h>
32aec9a0f1SJagan Teki #elif defined(CONFIG_ARCH_SUNXI)
336620377eSHans de Goede #include <asm/arch/i2c.h>
34306563a7SAlbert Aribaud #else
35306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board
3601ec99d9SAlbert Aribaud #endif
3714a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
3801ec99d9SAlbert Aribaud
3901ec99d9SAlbert Aribaud /*
40a8f01ccfSJernej Skrabec * On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to
41a8f01ccfSJernej Skrabec * always have it.
42a8f01ccfSJernej Skrabec */
43a8f01ccfSJernej Skrabec #if defined(CONFIG_DM_I2C) && defined(CONFIG_ARCH_SUNXI)
44a8f01ccfSJernej Skrabec #include <asm/arch/i2c.h>
45a8f01ccfSJernej Skrabec #endif
46a8f01ccfSJernej Skrabec
47a8f01ccfSJernej Skrabec /*
48306563a7SAlbert Aribaud * TWSI register structure
4901ec99d9SAlbert Aribaud */
5001ec99d9SAlbert Aribaud
51aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI
526620377eSHans de Goede
536620377eSHans de Goede struct mvtwsi_registers {
546620377eSHans de Goede u32 slave_address;
556620377eSHans de Goede u32 xtnd_slave_addr;
566620377eSHans de Goede u32 data;
576620377eSHans de Goede u32 control;
586620377eSHans de Goede u32 status;
596620377eSHans de Goede u32 baudrate;
606620377eSHans de Goede u32 soft_reset;
616620377eSHans de Goede };
626620377eSHans de Goede
636620377eSHans de Goede #else
646620377eSHans de Goede
65306563a7SAlbert Aribaud struct mvtwsi_registers {
66306563a7SAlbert Aribaud u32 slave_address;
67306563a7SAlbert Aribaud u32 data;
68306563a7SAlbert Aribaud u32 control;
69306563a7SAlbert Aribaud union {
7049c801bfSmario.six@gdsys.cc u32 status; /* When reading */
7149c801bfSmario.six@gdsys.cc u32 baudrate; /* When writing */
72306563a7SAlbert Aribaud };
73306563a7SAlbert Aribaud u32 xtnd_slave_addr;
74306563a7SAlbert Aribaud u32 reserved[2];
75306563a7SAlbert Aribaud u32 soft_reset;
76306563a7SAlbert Aribaud };
77306563a7SAlbert Aribaud
786620377eSHans de Goede #endif
796620377eSHans de Goede
8014a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
8114a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
8214a6ff2cSmario.six@gdsys.cc /* TWSI Register base for the device */
8314a6ff2cSmario.six@gdsys.cc struct mvtwsi_registers *base;
8414a6ff2cSmario.six@gdsys.cc /* Number of the device (determined from cell-index property) */
8514a6ff2cSmario.six@gdsys.cc int index;
8614a6ff2cSmario.six@gdsys.cc /* The I2C slave address for the device */
8714a6ff2cSmario.six@gdsys.cc u8 slaveadd;
8814a6ff2cSmario.six@gdsys.cc /* The configured I2C speed in Hz */
8914a6ff2cSmario.six@gdsys.cc uint speed;
90c68c6243Smario.six@gdsys.cc /* The current length of a clock period (depending on speed) */
91c68c6243Smario.six@gdsys.cc uint tick;
9214a6ff2cSmario.six@gdsys.cc };
9314a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
9414a6ff2cSmario.six@gdsys.cc
95306563a7SAlbert Aribaud /*
96dfc3958cSmario.six@gdsys.cc * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
97dfc3958cSmario.six@gdsys.cc * register
98306563a7SAlbert Aribaud */
99dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
100dfc3958cSmario.six@gdsys.cc /* Acknowledge bit */
101dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_ACK = 0x00000004,
102dfc3958cSmario.six@gdsys.cc /* Interrupt flag */
103dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_IFLG = 0x00000008,
104dfc3958cSmario.six@gdsys.cc /* Stop bit */
105dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_STOP = 0x00000010,
106dfc3958cSmario.six@gdsys.cc /* Start bit */
107dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_START = 0x00000020,
108dfc3958cSmario.six@gdsys.cc /* I2C enable */
109dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_TWSIEN = 0x00000040,
110dfc3958cSmario.six@gdsys.cc /* Interrupt enable */
111dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_INTEN = 0x00000080,
112dfc3958cSmario.six@gdsys.cc };
113306563a7SAlbert Aribaud
114306563a7SAlbert Aribaud /*
11549c801bfSmario.six@gdsys.cc * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
11649c801bfSmario.six@gdsys.cc * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
117904dfbfdSHans de Goede */
118904dfbfdSHans de Goede
119904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
120904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
121904dfbfdSHans de Goede #else
122904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
123904dfbfdSHans de Goede #endif
124904dfbfdSHans de Goede
125904dfbfdSHans de Goede /*
126dfc3958cSmario.six@gdsys.cc * enum mvstwsi_status_values - Possible values of I2C controller's status
127dfc3958cSmario.six@gdsys.cc * register
128dfc3958cSmario.six@gdsys.cc *
129dfc3958cSmario.six@gdsys.cc * Only those statuses expected in normal master operation on
130dfc3958cSmario.six@gdsys.cc * non-10-bit-address devices are specified.
131dfc3958cSmario.six@gdsys.cc *
132dfc3958cSmario.six@gdsys.cc * Every status that's unexpected during normal operation (bus errors,
133dfc3958cSmario.six@gdsys.cc * arbitration losses, missing ACKs...) is passed back to the caller as an error
134306563a7SAlbert Aribaud * code.
135306563a7SAlbert Aribaud */
136dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
137dfc3958cSmario.six@gdsys.cc /* START condition transmitted */
138dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_START = 0x08,
139dfc3958cSmario.six@gdsys.cc /* Repeated START condition transmitted */
140dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_REPEATED_START = 0x10,
141dfc3958cSmario.six@gdsys.cc /* Address + write bit transmitted, ACK received */
142dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_W_ACK = 0x18,
143dfc3958cSmario.six@gdsys.cc /* Data transmitted, ACK received */
144dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK = 0x28,
145dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK received */
146dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_ACK = 0x40,
147dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK not received */
148dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_NAK = 0x48,
149dfc3958cSmario.six@gdsys.cc /* Data received, ACK transmitted */
150dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_ACK = 0x50,
151dfc3958cSmario.six@gdsys.cc /* Data received, ACK not transmitted */
152dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK = 0x58,
153dfc3958cSmario.six@gdsys.cc /* No relevant status */
154dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_IDLE = 0xF8,
155dfc3958cSmario.six@gdsys.cc };
156306563a7SAlbert Aribaud
157306563a7SAlbert Aribaud /*
158670514f5Smario.six@gdsys.cc * enum mvstwsi_ack_flags - Determine whether a read byte should be
159670514f5Smario.six@gdsys.cc * acknowledged or not.
160670514f5Smario.six@gdsys.cc */
161670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
162670514f5Smario.six@gdsys.cc /* Send NAK after received byte */
163670514f5Smario.six@gdsys.cc MVTWSI_READ_NAK = 0,
164670514f5Smario.six@gdsys.cc /* Send ACK after received byte */
165670514f5Smario.six@gdsys.cc MVTWSI_READ_ACK = 1,
166670514f5Smario.six@gdsys.cc };
167670514f5Smario.six@gdsys.cc
1686e677cafSmario.six@gdsys.cc /*
1696e677cafSmario.six@gdsys.cc * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
1706e677cafSmario.six@gdsys.cc *
1716e677cafSmario.six@gdsys.cc * @speed: The speed in Hz to calculate the clock cycle duration for.
1726e677cafSmario.six@gdsys.cc * @return The duration of a clock cycle in ns.
1736e677cafSmario.six@gdsys.cc */
calc_tick(uint speed)174c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed)
175c68c6243Smario.six@gdsys.cc {
176c68c6243Smario.six@gdsys.cc /* One tick = the duration of a period at the specified speed in ns (we
177c68c6243Smario.six@gdsys.cc * add 100 ns to be on the safe side) */
178c68c6243Smario.six@gdsys.cc return (1000000000u / speed) + 100;
179c68c6243Smario.six@gdsys.cc }
180c68c6243Smario.six@gdsys.cc
18114a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
182c68c6243Smario.six@gdsys.cc
183670514f5Smario.six@gdsys.cc /*
1846e677cafSmario.six@gdsys.cc * twsi_get_base() - Get controller register base for specified adapter
1856e677cafSmario.six@gdsys.cc *
1866e677cafSmario.six@gdsys.cc * @adap: Adapter to get the register base for.
1876e677cafSmario.six@gdsys.cc * @return Register base for the specified adapter.
188306563a7SAlbert Aribaud */
twsi_get_base(struct i2c_adapter * adap)189dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
190dd82242bSPaul Kocialkowski {
191dd82242bSPaul Kocialkowski switch (adap->hwadapnr) {
192dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
193dd82242bSPaul Kocialkowski case 0:
194dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
195dd82242bSPaul Kocialkowski #endif
196dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
197dd82242bSPaul Kocialkowski case 1:
198dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
199dd82242bSPaul Kocialkowski #endif
200dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
201dd82242bSPaul Kocialkowski case 2:
202dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
203dd82242bSPaul Kocialkowski #endif
204dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
205dd82242bSPaul Kocialkowski case 3:
206dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
207dd82242bSPaul Kocialkowski #endif
208dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
209dd82242bSPaul Kocialkowski case 4:
210dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
211dd82242bSPaul Kocialkowski #endif
2129d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
2139d082687SJelle van der Waa case 5:
2149d082687SJelle van der Waa return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
2159d082687SJelle van der Waa #endif
216dd82242bSPaul Kocialkowski default:
217dd82242bSPaul Kocialkowski printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
218dd82242bSPaul Kocialkowski break;
219dd82242bSPaul Kocialkowski }
220dd82242bSPaul Kocialkowski
221dd82242bSPaul Kocialkowski return NULL;
222dd82242bSPaul Kocialkowski }
22314a6ff2cSmario.six@gdsys.cc #endif
224306563a7SAlbert Aribaud
225306563a7SAlbert Aribaud /*
226dfc3958cSmario.six@gdsys.cc * enum mvtwsi_error_class - types of I2C errors
227306563a7SAlbert Aribaud */
228dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
229dfc3958cSmario.six@gdsys.cc /* The controller returned a different status than expected */
230dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_WRONG_STATUS = 0x01,
231dfc3958cSmario.six@gdsys.cc /* The controller timed out */
232dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_TIMEOUT = 0x02,
233dfc3958cSmario.six@gdsys.cc };
234306563a7SAlbert Aribaud
235dfc3958cSmario.six@gdsys.cc /*
236dfc3958cSmario.six@gdsys.cc * mvtwsi_error() - Build I2C return code from error information
237dfc3958cSmario.six@gdsys.cc *
238dfc3958cSmario.six@gdsys.cc * For debugging purposes, this function packs some information of an occurred
239dfc3958cSmario.six@gdsys.cc * error into a return code. These error codes are returned from I2C API
240dfc3958cSmario.six@gdsys.cc * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
241dfc3958cSmario.six@gdsys.cc *
242dfc3958cSmario.six@gdsys.cc * @ec: The error class of the error (enum mvtwsi_error_class).
243dfc3958cSmario.six@gdsys.cc * @lc: The last value of the control register.
244dfc3958cSmario.six@gdsys.cc * @ls: The last value of the status register.
245dfc3958cSmario.six@gdsys.cc * @es: The expected value of the status register.
246dfc3958cSmario.six@gdsys.cc * @return The generated error code.
247dfc3958cSmario.six@gdsys.cc */
mvtwsi_error(uint ec,uint lc,uint ls,uint es)248dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
249dfc3958cSmario.six@gdsys.cc {
250dfc3958cSmario.six@gdsys.cc return ((ec << 24) & 0xFF000000)
251dfc3958cSmario.six@gdsys.cc | ((lc << 16) & 0x00FF0000)
252dfc3958cSmario.six@gdsys.cc | ((ls << 8) & 0x0000FF00)
253dfc3958cSmario.six@gdsys.cc | (es & 0xFF);
254dfc3958cSmario.six@gdsys.cc }
255306563a7SAlbert Aribaud
256306563a7SAlbert Aribaud /*
2576e677cafSmario.six@gdsys.cc * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
2586e677cafSmario.six@gdsys.cc *
2596e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
2606e677cafSmario.six@gdsys.cc * out occurred, or the status was not the expected one.
261306563a7SAlbert Aribaud */
twsi_wait(struct mvtwsi_registers * twsi,int expected_status,uint tick)262c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
263c68c6243Smario.six@gdsys.cc uint tick)
26401ec99d9SAlbert Aribaud {
265306563a7SAlbert Aribaud int control, status;
266306563a7SAlbert Aribaud int timeout = 1000;
267306563a7SAlbert Aribaud
268306563a7SAlbert Aribaud do {
269306563a7SAlbert Aribaud control = readl(&twsi->control);
270306563a7SAlbert Aribaud if (control & MVTWSI_CONTROL_IFLG) {
271306563a7SAlbert Aribaud status = readl(&twsi->status);
272306563a7SAlbert Aribaud if (status == expected_status)
273306563a7SAlbert Aribaud return 0;
27401ec99d9SAlbert Aribaud else
275dfc3958cSmario.six@gdsys.cc return mvtwsi_error(
276306563a7SAlbert Aribaud MVTWSI_ERROR_WRONG_STATUS,
277306563a7SAlbert Aribaud control, status, expected_status);
278306563a7SAlbert Aribaud }
279c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */
280306563a7SAlbert Aribaud } while (timeout--);
281306563a7SAlbert Aribaud status = readl(&twsi->status);
282dfc3958cSmario.six@gdsys.cc return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
283dfc3958cSmario.six@gdsys.cc expected_status);
28401ec99d9SAlbert Aribaud }
28501ec99d9SAlbert Aribaud
286306563a7SAlbert Aribaud /*
2876e677cafSmario.six@gdsys.cc * twsi_start() - Assert a START condition on the bus.
2886e677cafSmario.six@gdsys.cc *
2896e677cafSmario.six@gdsys.cc * This function is used in both single I2C transactions and inside
2906e677cafSmario.six@gdsys.cc * back-to-back transactions (repeated starts).
2916e677cafSmario.six@gdsys.cc *
2926e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
2936e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the
2946e677cafSmario.six@gdsys.cc * operation completion.
2956e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
2966e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
2976e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
298306563a7SAlbert Aribaud */
twsi_start(struct mvtwsi_registers * twsi,int expected_status,uint tick)299c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
300c68c6243Smario.six@gdsys.cc uint tick)
301306563a7SAlbert Aribaud {
30249c801bfSmario.six@gdsys.cc /* Assert START */
303670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
3042ca02995SHans de Goede MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
30549c801bfSmario.six@gdsys.cc /* Wait for controller to process START */
306c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick);
307306563a7SAlbert Aribaud }
308306563a7SAlbert Aribaud
309306563a7SAlbert Aribaud /*
3106e677cafSmario.six@gdsys.cc * twsi_send() - Send a byte on the I2C bus.
3116e677cafSmario.six@gdsys.cc *
3126e677cafSmario.six@gdsys.cc * The byte may be part of an address byte or data.
3136e677cafSmario.six@gdsys.cc *
3146e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3156e677cafSmario.six@gdsys.cc * @byte: The byte to send.
3166e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the
3176e677cafSmario.six@gdsys.cc * operation completion.
3186e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3196e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
3206e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
321306563a7SAlbert Aribaud */
twsi_send(struct mvtwsi_registers * twsi,u8 byte,int expected_status,uint tick)3223c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
323c68c6243Smario.six@gdsys.cc int expected_status, uint tick)
324306563a7SAlbert Aribaud {
32549c801bfSmario.six@gdsys.cc /* Write byte to data register for sending */
326306563a7SAlbert Aribaud writel(byte, &twsi->data);
32749c801bfSmario.six@gdsys.cc /* Clear any pending interrupt -- that will cause sending */
328670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
329670514f5Smario.six@gdsys.cc &twsi->control);
33049c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and check ACK */
331c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick);
332306563a7SAlbert Aribaud }
333306563a7SAlbert Aribaud
334306563a7SAlbert Aribaud /*
3356e677cafSmario.six@gdsys.cc * twsi_recv() - Receive a byte on the I2C bus.
3366e677cafSmario.six@gdsys.cc *
3376e677cafSmario.six@gdsys.cc * The static variable mvtwsi_control_flags controls whether we ack or nak.
3386e677cafSmario.six@gdsys.cc *
3396e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3406e677cafSmario.six@gdsys.cc * @byte: The byte to send.
3416e677cafSmario.six@gdsys.cc * @ack_flag: Flag that determines whether the received byte should
3426e677cafSmario.six@gdsys.cc * be acknowledged by the controller or not (sent ACK/NAK).
3436e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3446e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
3456e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
346306563a7SAlbert Aribaud */
twsi_recv(struct mvtwsi_registers * twsi,u8 * byte,int ack_flag,uint tick)347c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
348c68c6243Smario.six@gdsys.cc uint tick)
349306563a7SAlbert Aribaud {
350670514f5Smario.six@gdsys.cc int expected_status, status, control;
351306563a7SAlbert Aribaud
352670514f5Smario.six@gdsys.cc /* Compute expected status based on passed ACK flag */
353670514f5Smario.six@gdsys.cc expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
354670514f5Smario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK;
35549c801bfSmario.six@gdsys.cc /* Acknowledge *previous state*, and launch receive */
356670514f5Smario.six@gdsys.cc control = MVTWSI_CONTROL_TWSIEN;
357670514f5Smario.six@gdsys.cc control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
358670514f5Smario.six@gdsys.cc writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
35949c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and assert ACK or NAK */
360c68c6243Smario.six@gdsys.cc status = twsi_wait(twsi, expected_status, tick);
36149c801bfSmario.six@gdsys.cc /* If we did receive the expected byte, store it */
362306563a7SAlbert Aribaud if (status == 0)
363306563a7SAlbert Aribaud *byte = readl(&twsi->data);
364306563a7SAlbert Aribaud return status;
365306563a7SAlbert Aribaud }
366306563a7SAlbert Aribaud
367306563a7SAlbert Aribaud /*
3686e677cafSmario.six@gdsys.cc * twsi_stop() - Assert a STOP condition on the bus.
3696e677cafSmario.six@gdsys.cc *
3706e677cafSmario.six@gdsys.cc * This function is also used to force the bus back to idle state (SDA =
3716e677cafSmario.six@gdsys.cc * SCL = 1).
3726e677cafSmario.six@gdsys.cc *
3736e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3746e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3756e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out
3766e677cafSmario.six@gdsys.cc * occurred.
377306563a7SAlbert Aribaud */
twsi_stop(struct mvtwsi_registers * twsi,uint tick)378c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
379306563a7SAlbert Aribaud {
380306563a7SAlbert Aribaud int control, stop_status;
381059fce9fSmario.six@gdsys.cc int status = 0;
382306563a7SAlbert Aribaud int timeout = 1000;
383306563a7SAlbert Aribaud
38449c801bfSmario.six@gdsys.cc /* Assert STOP */
385306563a7SAlbert Aribaud control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
386904dfbfdSHans de Goede writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
38749c801bfSmario.six@gdsys.cc /* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
388306563a7SAlbert Aribaud do {
389306563a7SAlbert Aribaud stop_status = readl(&twsi->status);
390306563a7SAlbert Aribaud if (stop_status == MVTWSI_STATUS_IDLE)
391306563a7SAlbert Aribaud break;
392c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */
393306563a7SAlbert Aribaud } while (timeout--);
394306563a7SAlbert Aribaud control = readl(&twsi->control);
395306563a7SAlbert Aribaud if (stop_status != MVTWSI_STATUS_IDLE)
396059fce9fSmario.six@gdsys.cc status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
397306563a7SAlbert Aribaud control, status, MVTWSI_STATUS_IDLE);
398306563a7SAlbert Aribaud return status;
399306563a7SAlbert Aribaud }
400306563a7SAlbert Aribaud
4016e677cafSmario.six@gdsys.cc /*
4026e677cafSmario.six@gdsys.cc * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
4036e677cafSmario.six@gdsys.cc *
4046e677cafSmario.six@gdsys.cc * @n: Parameter 'n' for the frequency calculation algorithm.
4056e677cafSmario.six@gdsys.cc * @m: Parameter 'm' for the frequency calculation algorithm.
4066e677cafSmario.six@gdsys.cc * @return The I2C frequency corresponding to the passed m and n parameters.
4076e677cafSmario.six@gdsys.cc */
twsi_calc_freq(const int n,const int m)408e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
409f582a158SStefan Roese {
410aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI
411f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
412f582a158SStefan Roese #else
413f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
414f582a158SStefan Roese #endif
415f582a158SStefan Roese }
416306563a7SAlbert Aribaud
417306563a7SAlbert Aribaud /*
4186e677cafSmario.six@gdsys.cc * twsi_reset() - Reset the I2C controller.
4196e677cafSmario.six@gdsys.cc *
4206e677cafSmario.six@gdsys.cc * Resetting the controller also resets the baud rate and slave address, hence
4216e677cafSmario.six@gdsys.cc * they must be re-established after the reset.
4226e677cafSmario.six@gdsys.cc *
4236e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
424306563a7SAlbert Aribaud */
twsi_reset(struct mvtwsi_registers * twsi)4253c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
426306563a7SAlbert Aribaud {
42749c801bfSmario.six@gdsys.cc /* Reset controller */
428306563a7SAlbert Aribaud writel(0, &twsi->soft_reset);
42949c801bfSmario.six@gdsys.cc /* Wait 2 ms -- this is what the Marvell LSP does */
430306563a7SAlbert Aribaud udelay(20000);
431306563a7SAlbert Aribaud }
432306563a7SAlbert Aribaud
433306563a7SAlbert Aribaud /*
4346e677cafSmario.six@gdsys.cc * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
4356e677cafSmario.six@gdsys.cc *
4366e677cafSmario.six@gdsys.cc * This function sets baud rate to the highest possible value that does not
4376e677cafSmario.six@gdsys.cc * exceed the requested rate.
4386e677cafSmario.six@gdsys.cc *
4396e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
4406e677cafSmario.six@gdsys.cc * @requested_speed: The desired frequency the controller should run at
4416e677cafSmario.six@gdsys.cc * in Hz.
4426e677cafSmario.six@gdsys.cc * @return The actual frequency the controller was configured to.
443306563a7SAlbert Aribaud */
__twsi_i2c_set_bus_speed(struct mvtwsi_registers * twsi,uint requested_speed)4443c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
445e0758281Smario.six@gdsys.cc uint requested_speed)
446306563a7SAlbert Aribaud {
447e0758281Smario.six@gdsys.cc uint tmp_speed, highest_speed, n, m;
448e0758281Smario.six@gdsys.cc uint baud = 0x44; /* Baud rate after controller reset */
449306563a7SAlbert Aribaud
450306563a7SAlbert Aribaud highest_speed = 0;
45149c801bfSmario.six@gdsys.cc /* Successively try m, n combinations, and use the combination
45249c801bfSmario.six@gdsys.cc * resulting in the largest speed that's not above the requested
45349c801bfSmario.six@gdsys.cc * speed */
45401ec99d9SAlbert Aribaud for (n = 0; n < 8; n++) {
45501ec99d9SAlbert Aribaud for (m = 0; m < 16; m++) {
456f582a158SStefan Roese tmp_speed = twsi_calc_freq(n, m);
4579ec43b0cSmario.six@gdsys.cc if ((tmp_speed <= requested_speed) &&
4589ec43b0cSmario.six@gdsys.cc (tmp_speed > highest_speed)) {
459306563a7SAlbert Aribaud highest_speed = tmp_speed;
460306563a7SAlbert Aribaud baud = (m << 3) | n;
46101ec99d9SAlbert Aribaud }
46201ec99d9SAlbert Aribaud }
46301ec99d9SAlbert Aribaud }
4640db2bbdcSHans de Goede writel(baud, &twsi->baudrate);
465c68c6243Smario.six@gdsys.cc
466c68c6243Smario.six@gdsys.cc /* Wait for controller for one tick */
467c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
468c68c6243Smario.six@gdsys.cc ndelay(calc_tick(highest_speed));
469c68c6243Smario.six@gdsys.cc #else
470c68c6243Smario.six@gdsys.cc ndelay(10000);
471c68c6243Smario.six@gdsys.cc #endif
472c68c6243Smario.six@gdsys.cc return highest_speed;
4730db2bbdcSHans de Goede }
4740db2bbdcSHans de Goede
4756e677cafSmario.six@gdsys.cc /*
4766e677cafSmario.six@gdsys.cc * __twsi_i2c_init() - Initialize the I2C controller.
4776e677cafSmario.six@gdsys.cc *
4786e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
4796e677cafSmario.six@gdsys.cc * @speed: The initial frequency the controller should run at
4806e677cafSmario.six@gdsys.cc * in Hz.
4816e677cafSmario.six@gdsys.cc * @slaveadd: The I2C address to be set for the I2C master.
4826e677cafSmario.six@gdsys.cc * @actual_speed: A output parameter that receives the actual frequency
4836e677cafSmario.six@gdsys.cc * in Hz the controller was set to by the function.
4846e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out
4856e677cafSmario.six@gdsys.cc * occurred.
4866e677cafSmario.six@gdsys.cc */
__twsi_i2c_init(struct mvtwsi_registers * twsi,int speed,int slaveadd,uint * actual_speed)4873c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
488c68c6243Smario.six@gdsys.cc int slaveadd, uint *actual_speed)
4890db2bbdcSHans de Goede {
49049c801bfSmario.six@gdsys.cc /* Reset controller */
4913c4db636Smario.six@gdsys.cc twsi_reset(twsi);
49249c801bfSmario.six@gdsys.cc /* Set speed */
493c68c6243Smario.six@gdsys.cc *actual_speed = __twsi_i2c_set_bus_speed(twsi, speed);
49449c801bfSmario.six@gdsys.cc /* Set slave address; even though we don't use it */
4950db2bbdcSHans de Goede writel(slaveadd, &twsi->slave_address);
4960db2bbdcSHans de Goede writel(0, &twsi->xtnd_slave_addr);
49749c801bfSmario.six@gdsys.cc /* Assert STOP, but don't care for the result */
498c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
499c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, calc_tick(*actual_speed));
500c68c6243Smario.six@gdsys.cc #else
501c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, 10000);
502c68c6243Smario.six@gdsys.cc #endif
50301ec99d9SAlbert Aribaud }
50401ec99d9SAlbert Aribaud
50501ec99d9SAlbert Aribaud /*
5066e677cafSmario.six@gdsys.cc * i2c_begin() - Start a I2C transaction.
5076e677cafSmario.six@gdsys.cc *
5086e677cafSmario.six@gdsys.cc * Begin a I2C transaction with a given expected start status and chip address.
5096e677cafSmario.six@gdsys.cc * A START is asserted, and the address byte is sent to the I2C controller. The
5106e677cafSmario.six@gdsys.cc * expected address status will be derived from the direction bit (bit 0) of
5116e677cafSmario.six@gdsys.cc * the address byte.
5126e677cafSmario.six@gdsys.cc *
5136e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5146e677cafSmario.six@gdsys.cc * @expected_start_status: The I2C status the controller is expected to
5156e677cafSmario.six@gdsys.cc * assert after the address byte was sent.
5166e677cafSmario.six@gdsys.cc * @addr: The address byte to be sent.
5176e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current
5186e677cafSmario.six@gdsys.cc * I2C speed.
5196e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5206e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
52101ec99d9SAlbert Aribaud */
i2c_begin(struct mvtwsi_registers * twsi,int expected_start_status,u8 addr,uint tick)5223c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
523c68c6243Smario.six@gdsys.cc u8 addr, uint tick)
52401ec99d9SAlbert Aribaud {
525306563a7SAlbert Aribaud int status, expected_addr_status;
52601ec99d9SAlbert Aribaud
52749c801bfSmario.six@gdsys.cc /* Compute the expected address status from the direction bit in
52849c801bfSmario.six@gdsys.cc * the address byte */
52949c801bfSmario.six@gdsys.cc if (addr & 1) /* Reading */
530306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
53149c801bfSmario.six@gdsys.cc else /* Writing */
532306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
53349c801bfSmario.six@gdsys.cc /* Assert START */
534c68c6243Smario.six@gdsys.cc status = twsi_start(twsi, expected_start_status, tick);
53549c801bfSmario.six@gdsys.cc /* Send out the address if the start went well */
536306563a7SAlbert Aribaud if (status == 0)
537c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, addr, expected_addr_status, tick);
53849c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
539306563a7SAlbert Aribaud return status;
54001ec99d9SAlbert Aribaud }
54101ec99d9SAlbert Aribaud
542306563a7SAlbert Aribaud /*
5436e677cafSmario.six@gdsys.cc * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
5446e677cafSmario.six@gdsys.cc *
5456e677cafSmario.six@gdsys.cc * This function begins a I2C read transaction, does a dummy read and NAKs; if
5466e677cafSmario.six@gdsys.cc * the procedure succeeds, the chip is considered to be present.
5476e677cafSmario.six@gdsys.cc *
5486e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5496e677cafSmario.six@gdsys.cc * @chip: The chip address to probe.
5506e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
5516e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5526e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
553306563a7SAlbert Aribaud */
__twsi_i2c_probe_chip(struct mvtwsi_registers * twsi,uchar chip,uint tick)554c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
555c68c6243Smario.six@gdsys.cc uint tick)
55601ec99d9SAlbert Aribaud {
557306563a7SAlbert Aribaud u8 dummy_byte;
558306563a7SAlbert Aribaud int status;
55901ec99d9SAlbert Aribaud
56049c801bfSmario.six@gdsys.cc /* Begin i2c read */
561c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
56249c801bfSmario.six@gdsys.cc /* Dummy read was accepted: receive byte, but NAK it. */
563306563a7SAlbert Aribaud if (status == 0)
564c68c6243Smario.six@gdsys.cc status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
565306563a7SAlbert Aribaud /* Stop transaction */
566c68c6243Smario.six@gdsys.cc twsi_stop(twsi, tick);
56749c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
568306563a7SAlbert Aribaud return status;
56901ec99d9SAlbert Aribaud }
57001ec99d9SAlbert Aribaud
571306563a7SAlbert Aribaud /*
5726e677cafSmario.six@gdsys.cc * __twsi_i2c_read() - Read data from a I2C chip.
5736e677cafSmario.six@gdsys.cc *
5746e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address
5756e677cafSmario.six@gdsys.cc * bytes; then begins a I2C read transaction, and receives the data bytes.
576306563a7SAlbert Aribaud *
57749c801bfSmario.six@gdsys.cc * NOTE: Some devices want a stop right before the second start, while some
57849c801bfSmario.six@gdsys.cc * will choke if it is there. Since deciding this is not yet supported in
57949c801bfSmario.six@gdsys.cc * higher level APIs, we need to make a decision here, and for the moment that
58049c801bfSmario.six@gdsys.cc * will be a repeated start without a preceding stop.
5816e677cafSmario.six@gdsys.cc *
5826e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5836e677cafSmario.six@gdsys.cc * @chip: The chip address to read from.
5846e677cafSmario.six@gdsys.cc * @addr: The address bytes to send.
5856e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes.
5866e677cafSmario.six@gdsys.cc * @data: The buffer to receive the data read from the chip (has to have
5876e677cafSmario.six@gdsys.cc * a size of at least 'length' bytes).
5886e677cafSmario.six@gdsys.cc * @length: The amount of data to be read from the chip in bytes.
5896e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
5906e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5916e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
592306563a7SAlbert Aribaud */
__twsi_i2c_read(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)5933c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
594c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length,
595c68c6243Smario.six@gdsys.cc uint tick)
59601ec99d9SAlbert Aribaud {
597059fce9fSmario.six@gdsys.cc int status = 0;
598059fce9fSmario.six@gdsys.cc int stop_status;
59924f9c6bbSmario.six@gdsys.cc int expected_start = MVTWSI_STATUS_START;
60001ec99d9SAlbert Aribaud
60124f9c6bbSmario.six@gdsys.cc if (alen > 0) {
60249c801bfSmario.six@gdsys.cc /* Begin i2c write to send the address bytes */
603c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1), tick);
60449c801bfSmario.six@gdsys.cc /* Send address bytes */
605306563a7SAlbert Aribaud while ((status == 0) && alen--)
60603d6cd97SStefan Roese status = twsi_send(twsi, addr[alen],
607c68c6243Smario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK, tick);
60824f9c6bbSmario.six@gdsys.cc /* Send repeated STARTs after the initial START */
60924f9c6bbSmario.six@gdsys.cc expected_start = MVTWSI_STATUS_REPEATED_START;
61024f9c6bbSmario.six@gdsys.cc }
61149c801bfSmario.six@gdsys.cc /* Begin i2c read to receive data bytes */
612306563a7SAlbert Aribaud if (status == 0)
613c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
614670514f5Smario.six@gdsys.cc /* Receive actual data bytes; set NAK if we if we have nothing more to
615670514f5Smario.six@gdsys.cc * read */
616670514f5Smario.six@gdsys.cc while ((status == 0) && length--)
6173c4db636Smario.six@gdsys.cc status = twsi_recv(twsi, data++,
618670514f5Smario.six@gdsys.cc length > 0 ?
619c68c6243Smario.six@gdsys.cc MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
620306563a7SAlbert Aribaud /* Stop transaction */
621c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick);
62249c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
623059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status;
62401ec99d9SAlbert Aribaud }
62501ec99d9SAlbert Aribaud
626306563a7SAlbert Aribaud /*
6276e677cafSmario.six@gdsys.cc * __twsi_i2c_write() - Send data to a I2C chip.
6286e677cafSmario.six@gdsys.cc *
6296e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address
6306e677cafSmario.six@gdsys.cc * bytes; then begins a new I2C write transaction, and sends the data bytes.
6316e677cafSmario.six@gdsys.cc *
6326e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
6336e677cafSmario.six@gdsys.cc * @chip: The chip address to read from.
6346e677cafSmario.six@gdsys.cc * @addr: The address bytes to send.
6356e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes.
6366e677cafSmario.six@gdsys.cc * @data: The buffer containing the data to be sent to the chip.
6376e677cafSmario.six@gdsys.cc * @length: The length of data to be sent to the chip in bytes.
6386e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
6396e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
6406e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
641306563a7SAlbert Aribaud */
__twsi_i2c_write(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)6423c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
643c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length,
644c68c6243Smario.six@gdsys.cc uint tick)
64501ec99d9SAlbert Aribaud {
646059fce9fSmario.six@gdsys.cc int status, stop_status;
64701ec99d9SAlbert Aribaud
64849c801bfSmario.six@gdsys.cc /* Begin i2c write to send first the address bytes, then the
64949c801bfSmario.six@gdsys.cc * data bytes */
650c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
65149c801bfSmario.six@gdsys.cc /* Send address bytes */
652f8a10ed1Smario.six@gdsys.cc while ((status == 0) && (alen-- > 0))
65303d6cd97SStefan Roese status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
654c68c6243Smario.six@gdsys.cc tick);
65549c801bfSmario.six@gdsys.cc /* Send data bytes */
656306563a7SAlbert Aribaud while ((status == 0) && (length-- > 0))
657c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
658c68c6243Smario.six@gdsys.cc tick);
659306563a7SAlbert Aribaud /* Stop transaction */
660c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick);
66149c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
662059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status;
66301ec99d9SAlbert Aribaud }
66401ec99d9SAlbert Aribaud
66514a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
twsi_i2c_init(struct i2c_adapter * adap,int speed,int slaveadd)66661bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
66761bc02b2Smario.six@gdsys.cc int slaveadd)
66861bc02b2Smario.six@gdsys.cc {
6693c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
670c68c6243Smario.six@gdsys.cc __twsi_i2c_init(twsi, speed, slaveadd, NULL);
67161bc02b2Smario.six@gdsys.cc }
67261bc02b2Smario.six@gdsys.cc
twsi_i2c_set_bus_speed(struct i2c_adapter * adap,uint requested_speed)67361bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
67461bc02b2Smario.six@gdsys.cc uint requested_speed)
67561bc02b2Smario.six@gdsys.cc {
6763c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
677c68c6243Smario.six@gdsys.cc __twsi_i2c_set_bus_speed(twsi, requested_speed);
678c68c6243Smario.six@gdsys.cc return 0;
67961bc02b2Smario.six@gdsys.cc }
68061bc02b2Smario.six@gdsys.cc
twsi_i2c_probe(struct i2c_adapter * adap,uchar chip)68161bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
68261bc02b2Smario.six@gdsys.cc {
6833c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
684c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(twsi, chip, 10000);
68561bc02b2Smario.six@gdsys.cc }
68661bc02b2Smario.six@gdsys.cc
twsi_i2c_read(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)68761bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
68861bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length)
68961bc02b2Smario.six@gdsys.cc {
6903c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
691f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4];
692f8a10ed1Smario.six@gdsys.cc
693f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF;
694f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF;
695f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF;
696f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF;
697f8a10ed1Smario.six@gdsys.cc
698c68c6243Smario.six@gdsys.cc return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
699c68c6243Smario.six@gdsys.cc 10000);
70061bc02b2Smario.six@gdsys.cc }
70161bc02b2Smario.six@gdsys.cc
twsi_i2c_write(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)70261bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
70361bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length)
70461bc02b2Smario.six@gdsys.cc {
7053c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
706f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4];
707f8a10ed1Smario.six@gdsys.cc
708f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF;
709f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF;
710f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF;
711f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF;
712f8a10ed1Smario.six@gdsys.cc
713c68c6243Smario.six@gdsys.cc return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
714c68c6243Smario.six@gdsys.cc 10000);
71561bc02b2Smario.six@gdsys.cc }
71661bc02b2Smario.six@gdsys.cc
717dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
7180db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
7190db2bbdcSHans de Goede twsi_i2c_read, twsi_i2c_write,
7200db2bbdcSHans de Goede twsi_i2c_set_bus_speed,
7210db2bbdcSHans de Goede CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
722dd82242bSPaul Kocialkowski #endif
723dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
724dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
725dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write,
726dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed,
727dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
728dd82242bSPaul Kocialkowski
729dd82242bSPaul Kocialkowski #endif
730dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
731dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
732dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write,
733dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed,
734dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
735dd82242bSPaul Kocialkowski
736dd82242bSPaul Kocialkowski #endif
737dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
738dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
739dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write,
740dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed,
741dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
742dd82242bSPaul Kocialkowski
743dd82242bSPaul Kocialkowski #endif
744dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
745dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
746dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write,
747dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed,
748dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
749dd82242bSPaul Kocialkowski
750dd82242bSPaul Kocialkowski #endif
7519d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
7529d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
7539d082687SJelle van der Waa twsi_i2c_read, twsi_i2c_write,
7549d082687SJelle van der Waa twsi_i2c_set_bus_speed,
7559d082687SJelle van der Waa CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
7569d082687SJelle van der Waa
7579d082687SJelle van der Waa #endif
75814a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
75914a6ff2cSmario.six@gdsys.cc
76014a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
76114a6ff2cSmario.six@gdsys.cc u32 chip_flags)
76214a6ff2cSmario.six@gdsys.cc {
76314a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
764c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
76514a6ff2cSmario.six@gdsys.cc }
76614a6ff2cSmario.six@gdsys.cc
76714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
76814a6ff2cSmario.six@gdsys.cc {
76914a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
770c68c6243Smario.six@gdsys.cc
771c68c6243Smario.six@gdsys.cc dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
772c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed);
773c68c6243Smario.six@gdsys.cc
774c68c6243Smario.six@gdsys.cc return 0;
77514a6ff2cSmario.six@gdsys.cc }
77614a6ff2cSmario.six@gdsys.cc
77714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
77814a6ff2cSmario.six@gdsys.cc {
77914a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
78014a6ff2cSmario.six@gdsys.cc
781*a821c4afSSimon Glass dev->base = devfdt_get_addr_ptr(bus);
78214a6ff2cSmario.six@gdsys.cc
78314a6ff2cSmario.six@gdsys.cc if (!dev->base)
78414a6ff2cSmario.six@gdsys.cc return -ENOMEM;
78514a6ff2cSmario.six@gdsys.cc
786e160f7d4SSimon Glass dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
78714a6ff2cSmario.six@gdsys.cc "cell-index", -1);
788e160f7d4SSimon Glass dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
78914a6ff2cSmario.six@gdsys.cc "u-boot,i2c-slave-addr", 0x0);
790e160f7d4SSimon Glass dev->speed = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79114a6ff2cSmario.six@gdsys.cc "clock-frequency", 100000);
79214a6ff2cSmario.six@gdsys.cc return 0;
79314a6ff2cSmario.six@gdsys.cc }
79414a6ff2cSmario.six@gdsys.cc
79514a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
79614a6ff2cSmario.six@gdsys.cc {
79714a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
798c68c6243Smario.six@gdsys.cc uint actual_speed;
799c68c6243Smario.six@gdsys.cc
800c68c6243Smario.six@gdsys.cc __twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
801c68c6243Smario.six@gdsys.cc dev->speed = actual_speed;
802c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed);
80314a6ff2cSmario.six@gdsys.cc return 0;
80414a6ff2cSmario.six@gdsys.cc }
80514a6ff2cSmario.six@gdsys.cc
80614a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
80714a6ff2cSmario.six@gdsys.cc {
80814a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
80914a6ff2cSmario.six@gdsys.cc struct i2c_msg *dmsg, *omsg, dummy;
81014a6ff2cSmario.six@gdsys.cc
81114a6ff2cSmario.six@gdsys.cc memset(&dummy, 0, sizeof(struct i2c_msg));
81214a6ff2cSmario.six@gdsys.cc
81314a6ff2cSmario.six@gdsys.cc /* We expect either two messages (one with an offset and one with the
81414a6ff2cSmario.six@gdsys.cc * actual data) or one message (just data or offset/data combined) */
81514a6ff2cSmario.six@gdsys.cc if (nmsgs > 2 || nmsgs == 0) {
81614a6ff2cSmario.six@gdsys.cc debug("%s: Only one or two messages are supported.", __func__);
81714a6ff2cSmario.six@gdsys.cc return -1;
81814a6ff2cSmario.six@gdsys.cc }
81914a6ff2cSmario.six@gdsys.cc
82014a6ff2cSmario.six@gdsys.cc omsg = nmsgs == 1 ? &dummy : msg;
82114a6ff2cSmario.six@gdsys.cc dmsg = nmsgs == 1 ? msg : msg + 1;
82214a6ff2cSmario.six@gdsys.cc
82314a6ff2cSmario.six@gdsys.cc if (dmsg->flags & I2C_M_RD)
82414a6ff2cSmario.six@gdsys.cc return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
825c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len,
826c68c6243Smario.six@gdsys.cc dev->tick);
82714a6ff2cSmario.six@gdsys.cc else
82814a6ff2cSmario.six@gdsys.cc return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
829c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len,
830c68c6243Smario.six@gdsys.cc dev->tick);
83114a6ff2cSmario.six@gdsys.cc }
83214a6ff2cSmario.six@gdsys.cc
83314a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
83414a6ff2cSmario.six@gdsys.cc .xfer = mvtwsi_i2c_xfer,
83514a6ff2cSmario.six@gdsys.cc .probe_chip = mvtwsi_i2c_probe_chip,
83614a6ff2cSmario.six@gdsys.cc .set_bus_speed = mvtwsi_i2c_set_bus_speed,
83714a6ff2cSmario.six@gdsys.cc };
83814a6ff2cSmario.six@gdsys.cc
83914a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
84014a6ff2cSmario.six@gdsys.cc { .compatible = "marvell,mv64xxx-i2c", },
84187de0eb3SStefan Roese { .compatible = "marvell,mv78230-i2c", },
842a8f01ccfSJernej Skrabec { .compatible = "allwinner,sun6i-a31-i2c", },
84314a6ff2cSmario.six@gdsys.cc { /* sentinel */ }
84414a6ff2cSmario.six@gdsys.cc };
84514a6ff2cSmario.six@gdsys.cc
84614a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
84714a6ff2cSmario.six@gdsys.cc .name = "i2c_mvtwsi",
84814a6ff2cSmario.six@gdsys.cc .id = UCLASS_I2C,
84914a6ff2cSmario.six@gdsys.cc .of_match = mvtwsi_i2c_ids,
85014a6ff2cSmario.six@gdsys.cc .probe = mvtwsi_i2c_probe,
85114a6ff2cSmario.six@gdsys.cc .ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
85214a6ff2cSmario.six@gdsys.cc .priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
85314a6ff2cSmario.six@gdsys.cc .ops = &mvtwsi_i2c_ops,
85414a6ff2cSmario.six@gdsys.cc };
85514a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
856