183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
201ec99d9SAlbert Aribaud /*
3306563a7SAlbert Aribaud * Driver for the TWSI (i2c) controller found on the Marvell
4306563a7SAlbert Aribaud * orion5x and kirkwood SoC families.
501ec99d9SAlbert Aribaud *
657b4bce9SAlbert ARIBAUD * Author: Albert Aribaud <albert.u.boot@aribaud.net>
7306563a7SAlbert Aribaud * Copyright (c) 2010 Albert Aribaud.
801ec99d9SAlbert Aribaud */
9306563a7SAlbert Aribaud
1001ec99d9SAlbert Aribaud #include <common.h>
1101ec99d9SAlbert Aribaud #include <i2c.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
1301ec99d9SAlbert Aribaud #include <asm/io.h>
14*173ec351SBaruch Siach #include <linux/bitops.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;
61*173ec351SBaruch Siach u32 debug; /* Dummy field for build compatibility with mvebu */
626620377eSHans de Goede };
636620377eSHans de Goede
646620377eSHans de Goede #else
656620377eSHans de Goede
66306563a7SAlbert Aribaud struct mvtwsi_registers {
67306563a7SAlbert Aribaud u32 slave_address;
68306563a7SAlbert Aribaud u32 data;
69306563a7SAlbert Aribaud u32 control;
70306563a7SAlbert Aribaud union {
7149c801bfSmario.six@gdsys.cc u32 status; /* When reading */
7249c801bfSmario.six@gdsys.cc u32 baudrate; /* When writing */
73306563a7SAlbert Aribaud };
74306563a7SAlbert Aribaud u32 xtnd_slave_addr;
75*173ec351SBaruch Siach u32 reserved0[2];
76306563a7SAlbert Aribaud u32 soft_reset;
77*173ec351SBaruch Siach u32 reserved1[27];
78*173ec351SBaruch Siach u32 debug;
79306563a7SAlbert Aribaud };
80306563a7SAlbert Aribaud
816620377eSHans de Goede #endif
826620377eSHans de Goede
8314a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C
8414a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev {
8514a6ff2cSmario.six@gdsys.cc /* TWSI Register base for the device */
8614a6ff2cSmario.six@gdsys.cc struct mvtwsi_registers *base;
8714a6ff2cSmario.six@gdsys.cc /* Number of the device (determined from cell-index property) */
8814a6ff2cSmario.six@gdsys.cc int index;
8914a6ff2cSmario.six@gdsys.cc /* The I2C slave address for the device */
9014a6ff2cSmario.six@gdsys.cc u8 slaveadd;
9114a6ff2cSmario.six@gdsys.cc /* The configured I2C speed in Hz */
9214a6ff2cSmario.six@gdsys.cc uint speed;
93c68c6243Smario.six@gdsys.cc /* The current length of a clock period (depending on speed) */
94c68c6243Smario.six@gdsys.cc uint tick;
9514a6ff2cSmario.six@gdsys.cc };
9614a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
9714a6ff2cSmario.six@gdsys.cc
98306563a7SAlbert Aribaud /*
99dfc3958cSmario.six@gdsys.cc * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
100dfc3958cSmario.six@gdsys.cc * register
101306563a7SAlbert Aribaud */
102dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields {
103dfc3958cSmario.six@gdsys.cc /* Acknowledge bit */
104dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_ACK = 0x00000004,
105dfc3958cSmario.six@gdsys.cc /* Interrupt flag */
106dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_IFLG = 0x00000008,
107dfc3958cSmario.six@gdsys.cc /* Stop bit */
108dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_STOP = 0x00000010,
109dfc3958cSmario.six@gdsys.cc /* Start bit */
110dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_START = 0x00000020,
111dfc3958cSmario.six@gdsys.cc /* I2C enable */
112dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_TWSIEN = 0x00000040,
113dfc3958cSmario.six@gdsys.cc /* Interrupt enable */
114dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_INTEN = 0x00000080,
115dfc3958cSmario.six@gdsys.cc };
116306563a7SAlbert Aribaud
117306563a7SAlbert Aribaud /*
11849c801bfSmario.six@gdsys.cc * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
11949c801bfSmario.six@gdsys.cc * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
120904dfbfdSHans de Goede */
121904dfbfdSHans de Goede
122904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I
123904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
124904dfbfdSHans de Goede #else
125904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
126904dfbfdSHans de Goede #endif
127904dfbfdSHans de Goede
128904dfbfdSHans de Goede /*
129dfc3958cSmario.six@gdsys.cc * enum mvstwsi_status_values - Possible values of I2C controller's status
130dfc3958cSmario.six@gdsys.cc * register
131dfc3958cSmario.six@gdsys.cc *
132dfc3958cSmario.six@gdsys.cc * Only those statuses expected in normal master operation on
133dfc3958cSmario.six@gdsys.cc * non-10-bit-address devices are specified.
134dfc3958cSmario.six@gdsys.cc *
135dfc3958cSmario.six@gdsys.cc * Every status that's unexpected during normal operation (bus errors,
136dfc3958cSmario.six@gdsys.cc * arbitration losses, missing ACKs...) is passed back to the caller as an error
137306563a7SAlbert Aribaud * code.
138306563a7SAlbert Aribaud */
139dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values {
140dfc3958cSmario.six@gdsys.cc /* START condition transmitted */
141dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_START = 0x08,
142dfc3958cSmario.six@gdsys.cc /* Repeated START condition transmitted */
143dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_REPEATED_START = 0x10,
144dfc3958cSmario.six@gdsys.cc /* Address + write bit transmitted, ACK received */
145dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_W_ACK = 0x18,
146dfc3958cSmario.six@gdsys.cc /* Data transmitted, ACK received */
147dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK = 0x28,
148dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK received */
149dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_ACK = 0x40,
150dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK not received */
151dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_NAK = 0x48,
152dfc3958cSmario.six@gdsys.cc /* Data received, ACK transmitted */
153dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_ACK = 0x50,
154dfc3958cSmario.six@gdsys.cc /* Data received, ACK not transmitted */
155dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK = 0x58,
156dfc3958cSmario.six@gdsys.cc /* No relevant status */
157dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_IDLE = 0xF8,
158dfc3958cSmario.six@gdsys.cc };
159306563a7SAlbert Aribaud
160306563a7SAlbert Aribaud /*
161670514f5Smario.six@gdsys.cc * enum mvstwsi_ack_flags - Determine whether a read byte should be
162670514f5Smario.six@gdsys.cc * acknowledged or not.
163670514f5Smario.six@gdsys.cc */
164670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags {
165670514f5Smario.six@gdsys.cc /* Send NAK after received byte */
166670514f5Smario.six@gdsys.cc MVTWSI_READ_NAK = 0,
167670514f5Smario.six@gdsys.cc /* Send ACK after received byte */
168670514f5Smario.six@gdsys.cc MVTWSI_READ_ACK = 1,
169670514f5Smario.six@gdsys.cc };
170670514f5Smario.six@gdsys.cc
1716e677cafSmario.six@gdsys.cc /*
1726e677cafSmario.six@gdsys.cc * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
1736e677cafSmario.six@gdsys.cc *
1746e677cafSmario.six@gdsys.cc * @speed: The speed in Hz to calculate the clock cycle duration for.
1756e677cafSmario.six@gdsys.cc * @return The duration of a clock cycle in ns.
1766e677cafSmario.six@gdsys.cc */
calc_tick(uint speed)177c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed)
178c68c6243Smario.six@gdsys.cc {
179c68c6243Smario.six@gdsys.cc /* One tick = the duration of a period at the specified speed in ns (we
180c68c6243Smario.six@gdsys.cc * add 100 ns to be on the safe side) */
181c68c6243Smario.six@gdsys.cc return (1000000000u / speed) + 100;
182c68c6243Smario.six@gdsys.cc }
183c68c6243Smario.six@gdsys.cc
18414a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
185c68c6243Smario.six@gdsys.cc
186670514f5Smario.six@gdsys.cc /*
1876e677cafSmario.six@gdsys.cc * twsi_get_base() - Get controller register base for specified adapter
1886e677cafSmario.six@gdsys.cc *
1896e677cafSmario.six@gdsys.cc * @adap: Adapter to get the register base for.
1906e677cafSmario.six@gdsys.cc * @return Register base for the specified adapter.
191306563a7SAlbert Aribaud */
twsi_get_base(struct i2c_adapter * adap)192dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
193dd82242bSPaul Kocialkowski {
194dd82242bSPaul Kocialkowski switch (adap->hwadapnr) {
195dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
196dd82242bSPaul Kocialkowski case 0:
197dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
198dd82242bSPaul Kocialkowski #endif
199dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
200dd82242bSPaul Kocialkowski case 1:
201dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
202dd82242bSPaul Kocialkowski #endif
203dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
204dd82242bSPaul Kocialkowski case 2:
205dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
206dd82242bSPaul Kocialkowski #endif
207dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
208dd82242bSPaul Kocialkowski case 3:
209dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
210dd82242bSPaul Kocialkowski #endif
211dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
212dd82242bSPaul Kocialkowski case 4:
213dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
214dd82242bSPaul Kocialkowski #endif
2159d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
2169d082687SJelle van der Waa case 5:
2179d082687SJelle van der Waa return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
2189d082687SJelle van der Waa #endif
219dd82242bSPaul Kocialkowski default:
220dd82242bSPaul Kocialkowski printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
221dd82242bSPaul Kocialkowski break;
222dd82242bSPaul Kocialkowski }
223dd82242bSPaul Kocialkowski
224dd82242bSPaul Kocialkowski return NULL;
225dd82242bSPaul Kocialkowski }
22614a6ff2cSmario.six@gdsys.cc #endif
227306563a7SAlbert Aribaud
228306563a7SAlbert Aribaud /*
229dfc3958cSmario.six@gdsys.cc * enum mvtwsi_error_class - types of I2C errors
230306563a7SAlbert Aribaud */
231dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class {
232dfc3958cSmario.six@gdsys.cc /* The controller returned a different status than expected */
233dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_WRONG_STATUS = 0x01,
234dfc3958cSmario.six@gdsys.cc /* The controller timed out */
235dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_TIMEOUT = 0x02,
236dfc3958cSmario.six@gdsys.cc };
237306563a7SAlbert Aribaud
238dfc3958cSmario.six@gdsys.cc /*
239dfc3958cSmario.six@gdsys.cc * mvtwsi_error() - Build I2C return code from error information
240dfc3958cSmario.six@gdsys.cc *
241dfc3958cSmario.six@gdsys.cc * For debugging purposes, this function packs some information of an occurred
242dfc3958cSmario.six@gdsys.cc * error into a return code. These error codes are returned from I2C API
243dfc3958cSmario.six@gdsys.cc * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
244dfc3958cSmario.six@gdsys.cc *
245dfc3958cSmario.six@gdsys.cc * @ec: The error class of the error (enum mvtwsi_error_class).
246dfc3958cSmario.six@gdsys.cc * @lc: The last value of the control register.
247dfc3958cSmario.six@gdsys.cc * @ls: The last value of the status register.
248dfc3958cSmario.six@gdsys.cc * @es: The expected value of the status register.
249dfc3958cSmario.six@gdsys.cc * @return The generated error code.
250dfc3958cSmario.six@gdsys.cc */
mvtwsi_error(uint ec,uint lc,uint ls,uint es)251dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
252dfc3958cSmario.six@gdsys.cc {
253dfc3958cSmario.six@gdsys.cc return ((ec << 24) & 0xFF000000)
254dfc3958cSmario.six@gdsys.cc | ((lc << 16) & 0x00FF0000)
255dfc3958cSmario.six@gdsys.cc | ((ls << 8) & 0x0000FF00)
256dfc3958cSmario.six@gdsys.cc | (es & 0xFF);
257dfc3958cSmario.six@gdsys.cc }
258306563a7SAlbert Aribaud
259306563a7SAlbert Aribaud /*
2606e677cafSmario.six@gdsys.cc * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
2616e677cafSmario.six@gdsys.cc *
2626e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
2636e677cafSmario.six@gdsys.cc * out occurred, or the status was not the expected one.
264306563a7SAlbert Aribaud */
twsi_wait(struct mvtwsi_registers * twsi,int expected_status,uint tick)265c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
266c68c6243Smario.six@gdsys.cc uint tick)
26701ec99d9SAlbert Aribaud {
268306563a7SAlbert Aribaud int control, status;
269306563a7SAlbert Aribaud int timeout = 1000;
270306563a7SAlbert Aribaud
271306563a7SAlbert Aribaud do {
272306563a7SAlbert Aribaud control = readl(&twsi->control);
273306563a7SAlbert Aribaud if (control & MVTWSI_CONTROL_IFLG) {
274306563a7SAlbert Aribaud status = readl(&twsi->status);
275306563a7SAlbert Aribaud if (status == expected_status)
276306563a7SAlbert Aribaud return 0;
27701ec99d9SAlbert Aribaud else
278dfc3958cSmario.six@gdsys.cc return mvtwsi_error(
279306563a7SAlbert Aribaud MVTWSI_ERROR_WRONG_STATUS,
280306563a7SAlbert Aribaud control, status, expected_status);
281306563a7SAlbert Aribaud }
282c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */
283306563a7SAlbert Aribaud } while (timeout--);
284306563a7SAlbert Aribaud status = readl(&twsi->status);
285dfc3958cSmario.six@gdsys.cc return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
286dfc3958cSmario.six@gdsys.cc expected_status);
28701ec99d9SAlbert Aribaud }
28801ec99d9SAlbert Aribaud
289306563a7SAlbert Aribaud /*
2906e677cafSmario.six@gdsys.cc * twsi_start() - Assert a START condition on the bus.
2916e677cafSmario.six@gdsys.cc *
2926e677cafSmario.six@gdsys.cc * This function is used in both single I2C transactions and inside
2936e677cafSmario.six@gdsys.cc * back-to-back transactions (repeated starts).
2946e677cafSmario.six@gdsys.cc *
2956e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
2966e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the
2976e677cafSmario.six@gdsys.cc * operation completion.
2986e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
2996e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
3006e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
301306563a7SAlbert Aribaud */
twsi_start(struct mvtwsi_registers * twsi,int expected_status,uint tick)302c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
303c68c6243Smario.six@gdsys.cc uint tick)
304306563a7SAlbert Aribaud {
30549c801bfSmario.six@gdsys.cc /* Assert START */
306670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
3072ca02995SHans de Goede MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
30849c801bfSmario.six@gdsys.cc /* Wait for controller to process START */
309c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick);
310306563a7SAlbert Aribaud }
311306563a7SAlbert Aribaud
312306563a7SAlbert Aribaud /*
3136e677cafSmario.six@gdsys.cc * twsi_send() - Send a byte on the I2C bus.
3146e677cafSmario.six@gdsys.cc *
3156e677cafSmario.six@gdsys.cc * The byte may be part of an address byte or data.
3166e677cafSmario.six@gdsys.cc *
3176e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3186e677cafSmario.six@gdsys.cc * @byte: The byte to send.
3196e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the
3206e677cafSmario.six@gdsys.cc * operation completion.
3216e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3226e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
3236e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
324306563a7SAlbert Aribaud */
twsi_send(struct mvtwsi_registers * twsi,u8 byte,int expected_status,uint tick)3253c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
326c68c6243Smario.six@gdsys.cc int expected_status, uint tick)
327306563a7SAlbert Aribaud {
32849c801bfSmario.six@gdsys.cc /* Write byte to data register for sending */
329306563a7SAlbert Aribaud writel(byte, &twsi->data);
33049c801bfSmario.six@gdsys.cc /* Clear any pending interrupt -- that will cause sending */
331670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
332670514f5Smario.six@gdsys.cc &twsi->control);
33349c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and check ACK */
334c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick);
335306563a7SAlbert Aribaud }
336306563a7SAlbert Aribaud
337306563a7SAlbert Aribaud /*
3386e677cafSmario.six@gdsys.cc * twsi_recv() - Receive a byte on the I2C bus.
3396e677cafSmario.six@gdsys.cc *
3406e677cafSmario.six@gdsys.cc * The static variable mvtwsi_control_flags controls whether we ack or nak.
3416e677cafSmario.six@gdsys.cc *
3426e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3436e677cafSmario.six@gdsys.cc * @byte: The byte to send.
3446e677cafSmario.six@gdsys.cc * @ack_flag: Flag that determines whether the received byte should
3456e677cafSmario.six@gdsys.cc * be acknowledged by the controller or not (sent ACK/NAK).
3466e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3476e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time
3486e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one.
349306563a7SAlbert Aribaud */
twsi_recv(struct mvtwsi_registers * twsi,u8 * byte,int ack_flag,uint tick)350c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
351c68c6243Smario.six@gdsys.cc uint tick)
352306563a7SAlbert Aribaud {
353670514f5Smario.six@gdsys.cc int expected_status, status, control;
354306563a7SAlbert Aribaud
355670514f5Smario.six@gdsys.cc /* Compute expected status based on passed ACK flag */
356670514f5Smario.six@gdsys.cc expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
357670514f5Smario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK;
35849c801bfSmario.six@gdsys.cc /* Acknowledge *previous state*, and launch receive */
359670514f5Smario.six@gdsys.cc control = MVTWSI_CONTROL_TWSIEN;
360670514f5Smario.six@gdsys.cc control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
361670514f5Smario.six@gdsys.cc writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
36249c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and assert ACK or NAK */
363c68c6243Smario.six@gdsys.cc status = twsi_wait(twsi, expected_status, tick);
36449c801bfSmario.six@gdsys.cc /* If we did receive the expected byte, store it */
365306563a7SAlbert Aribaud if (status == 0)
366306563a7SAlbert Aribaud *byte = readl(&twsi->data);
367306563a7SAlbert Aribaud return status;
368306563a7SAlbert Aribaud }
369306563a7SAlbert Aribaud
370306563a7SAlbert Aribaud /*
3716e677cafSmario.six@gdsys.cc * twsi_stop() - Assert a STOP condition on the bus.
3726e677cafSmario.six@gdsys.cc *
3736e677cafSmario.six@gdsys.cc * This function is also used to force the bus back to idle state (SDA =
3746e677cafSmario.six@gdsys.cc * SCL = 1).
3756e677cafSmario.six@gdsys.cc *
3766e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
3776e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
3786e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out
3796e677cafSmario.six@gdsys.cc * occurred.
380306563a7SAlbert Aribaud */
twsi_stop(struct mvtwsi_registers * twsi,uint tick)381c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
382306563a7SAlbert Aribaud {
383306563a7SAlbert Aribaud int control, stop_status;
384059fce9fSmario.six@gdsys.cc int status = 0;
385306563a7SAlbert Aribaud int timeout = 1000;
386306563a7SAlbert Aribaud
38749c801bfSmario.six@gdsys.cc /* Assert STOP */
388306563a7SAlbert Aribaud control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
389904dfbfdSHans de Goede writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
39049c801bfSmario.six@gdsys.cc /* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
391306563a7SAlbert Aribaud do {
392306563a7SAlbert Aribaud stop_status = readl(&twsi->status);
393306563a7SAlbert Aribaud if (stop_status == MVTWSI_STATUS_IDLE)
394306563a7SAlbert Aribaud break;
395c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */
396306563a7SAlbert Aribaud } while (timeout--);
397306563a7SAlbert Aribaud control = readl(&twsi->control);
398306563a7SAlbert Aribaud if (stop_status != MVTWSI_STATUS_IDLE)
399059fce9fSmario.six@gdsys.cc status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
400306563a7SAlbert Aribaud control, status, MVTWSI_STATUS_IDLE);
401306563a7SAlbert Aribaud return status;
402306563a7SAlbert Aribaud }
403306563a7SAlbert Aribaud
4046e677cafSmario.six@gdsys.cc /*
4056e677cafSmario.six@gdsys.cc * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
4066e677cafSmario.six@gdsys.cc *
4076e677cafSmario.six@gdsys.cc * @n: Parameter 'n' for the frequency calculation algorithm.
4086e677cafSmario.six@gdsys.cc * @m: Parameter 'm' for the frequency calculation algorithm.
4096e677cafSmario.six@gdsys.cc * @return The I2C frequency corresponding to the passed m and n parameters.
4106e677cafSmario.six@gdsys.cc */
twsi_calc_freq(const int n,const int m)411e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m)
412f582a158SStefan Roese {
413aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI
414f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
415f582a158SStefan Roese #else
416f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
417f582a158SStefan Roese #endif
418f582a158SStefan Roese }
419306563a7SAlbert Aribaud
420306563a7SAlbert Aribaud /*
4216e677cafSmario.six@gdsys.cc * twsi_reset() - Reset the I2C controller.
4226e677cafSmario.six@gdsys.cc *
4236e677cafSmario.six@gdsys.cc * Resetting the controller also resets the baud rate and slave address, hence
4246e677cafSmario.six@gdsys.cc * they must be re-established after the reset.
4256e677cafSmario.six@gdsys.cc *
4266e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
427306563a7SAlbert Aribaud */
twsi_reset(struct mvtwsi_registers * twsi)4283c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi)
429306563a7SAlbert Aribaud {
43049c801bfSmario.six@gdsys.cc /* Reset controller */
431306563a7SAlbert Aribaud writel(0, &twsi->soft_reset);
43249c801bfSmario.six@gdsys.cc /* Wait 2 ms -- this is what the Marvell LSP does */
433306563a7SAlbert Aribaud udelay(20000);
434306563a7SAlbert Aribaud }
435306563a7SAlbert Aribaud
436306563a7SAlbert Aribaud /*
4376e677cafSmario.six@gdsys.cc * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
4386e677cafSmario.six@gdsys.cc *
4396e677cafSmario.six@gdsys.cc * This function sets baud rate to the highest possible value that does not
4406e677cafSmario.six@gdsys.cc * exceed the requested rate.
4416e677cafSmario.six@gdsys.cc *
4426e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
4436e677cafSmario.six@gdsys.cc * @requested_speed: The desired frequency the controller should run at
4446e677cafSmario.six@gdsys.cc * in Hz.
4456e677cafSmario.six@gdsys.cc * @return The actual frequency the controller was configured to.
446306563a7SAlbert Aribaud */
__twsi_i2c_set_bus_speed(struct mvtwsi_registers * twsi,uint requested_speed)4473c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
448e0758281Smario.six@gdsys.cc uint requested_speed)
449306563a7SAlbert Aribaud {
450e0758281Smario.six@gdsys.cc uint tmp_speed, highest_speed, n, m;
451e0758281Smario.six@gdsys.cc uint baud = 0x44; /* Baud rate after controller reset */
452306563a7SAlbert Aribaud
453306563a7SAlbert Aribaud highest_speed = 0;
45449c801bfSmario.six@gdsys.cc /* Successively try m, n combinations, and use the combination
45549c801bfSmario.six@gdsys.cc * resulting in the largest speed that's not above the requested
45649c801bfSmario.six@gdsys.cc * speed */
45701ec99d9SAlbert Aribaud for (n = 0; n < 8; n++) {
45801ec99d9SAlbert Aribaud for (m = 0; m < 16; m++) {
459f582a158SStefan Roese tmp_speed = twsi_calc_freq(n, m);
4609ec43b0cSmario.six@gdsys.cc if ((tmp_speed <= requested_speed) &&
4619ec43b0cSmario.six@gdsys.cc (tmp_speed > highest_speed)) {
462306563a7SAlbert Aribaud highest_speed = tmp_speed;
463306563a7SAlbert Aribaud baud = (m << 3) | n;
46401ec99d9SAlbert Aribaud }
46501ec99d9SAlbert Aribaud }
46601ec99d9SAlbert Aribaud }
4670db2bbdcSHans de Goede writel(baud, &twsi->baudrate);
468c68c6243Smario.six@gdsys.cc
469c68c6243Smario.six@gdsys.cc /* Wait for controller for one tick */
470c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
471c68c6243Smario.six@gdsys.cc ndelay(calc_tick(highest_speed));
472c68c6243Smario.six@gdsys.cc #else
473c68c6243Smario.six@gdsys.cc ndelay(10000);
474c68c6243Smario.six@gdsys.cc #endif
475c68c6243Smario.six@gdsys.cc return highest_speed;
4760db2bbdcSHans de Goede }
4770db2bbdcSHans de Goede
4786e677cafSmario.six@gdsys.cc /*
4796e677cafSmario.six@gdsys.cc * __twsi_i2c_init() - Initialize the I2C controller.
4806e677cafSmario.six@gdsys.cc *
4816e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
4826e677cafSmario.six@gdsys.cc * @speed: The initial frequency the controller should run at
4836e677cafSmario.six@gdsys.cc * in Hz.
4846e677cafSmario.six@gdsys.cc * @slaveadd: The I2C address to be set for the I2C master.
4856e677cafSmario.six@gdsys.cc * @actual_speed: A output parameter that receives the actual frequency
4866e677cafSmario.six@gdsys.cc * in Hz the controller was set to by the function.
4876e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out
4886e677cafSmario.six@gdsys.cc * occurred.
4896e677cafSmario.six@gdsys.cc */
__twsi_i2c_init(struct mvtwsi_registers * twsi,int speed,int slaveadd,uint * actual_speed)4903c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
491c68c6243Smario.six@gdsys.cc int slaveadd, uint *actual_speed)
4920db2bbdcSHans de Goede {
493004b4cdaSStefan Mavrodiev uint tmp_speed;
494004b4cdaSStefan Mavrodiev
49549c801bfSmario.six@gdsys.cc /* Reset controller */
4963c4db636Smario.six@gdsys.cc twsi_reset(twsi);
49749c801bfSmario.six@gdsys.cc /* Set speed */
498004b4cdaSStefan Mavrodiev tmp_speed = __twsi_i2c_set_bus_speed(twsi, speed);
4998bcf12ccSHeinrich Schuchardt if (actual_speed)
500004b4cdaSStefan Mavrodiev *actual_speed = tmp_speed;
50149c801bfSmario.six@gdsys.cc /* Set slave address; even though we don't use it */
5020db2bbdcSHans de Goede writel(slaveadd, &twsi->slave_address);
5030db2bbdcSHans de Goede writel(0, &twsi->xtnd_slave_addr);
50449c801bfSmario.six@gdsys.cc /* Assert STOP, but don't care for the result */
505c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C
506c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, calc_tick(*actual_speed));
507c68c6243Smario.six@gdsys.cc #else
508c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, 10000);
509c68c6243Smario.six@gdsys.cc #endif
51001ec99d9SAlbert Aribaud }
51101ec99d9SAlbert Aribaud
51201ec99d9SAlbert Aribaud /*
5136e677cafSmario.six@gdsys.cc * i2c_begin() - Start a I2C transaction.
5146e677cafSmario.six@gdsys.cc *
5156e677cafSmario.six@gdsys.cc * Begin a I2C transaction with a given expected start status and chip address.
5166e677cafSmario.six@gdsys.cc * A START is asserted, and the address byte is sent to the I2C controller. The
5176e677cafSmario.six@gdsys.cc * expected address status will be derived from the direction bit (bit 0) of
5186e677cafSmario.six@gdsys.cc * the address byte.
5196e677cafSmario.six@gdsys.cc *
5206e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5216e677cafSmario.six@gdsys.cc * @expected_start_status: The I2C status the controller is expected to
5226e677cafSmario.six@gdsys.cc * assert after the address byte was sent.
5236e677cafSmario.six@gdsys.cc * @addr: The address byte to be sent.
5246e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current
5256e677cafSmario.six@gdsys.cc * I2C speed.
5266e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5276e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
52801ec99d9SAlbert Aribaud */
i2c_begin(struct mvtwsi_registers * twsi,int expected_start_status,u8 addr,uint tick)5293c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
530c68c6243Smario.six@gdsys.cc u8 addr, uint tick)
53101ec99d9SAlbert Aribaud {
532306563a7SAlbert Aribaud int status, expected_addr_status;
53301ec99d9SAlbert Aribaud
53449c801bfSmario.six@gdsys.cc /* Compute the expected address status from the direction bit in
53549c801bfSmario.six@gdsys.cc * the address byte */
53649c801bfSmario.six@gdsys.cc if (addr & 1) /* Reading */
537306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
53849c801bfSmario.six@gdsys.cc else /* Writing */
539306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
54049c801bfSmario.six@gdsys.cc /* Assert START */
541c68c6243Smario.six@gdsys.cc status = twsi_start(twsi, expected_start_status, tick);
54249c801bfSmario.six@gdsys.cc /* Send out the address if the start went well */
543306563a7SAlbert Aribaud if (status == 0)
544c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, addr, expected_addr_status, tick);
54549c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
546306563a7SAlbert Aribaud return status;
54701ec99d9SAlbert Aribaud }
54801ec99d9SAlbert Aribaud
549306563a7SAlbert Aribaud /*
5506e677cafSmario.six@gdsys.cc * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
5516e677cafSmario.six@gdsys.cc *
5526e677cafSmario.six@gdsys.cc * This function begins a I2C read transaction, does a dummy read and NAKs; if
5536e677cafSmario.six@gdsys.cc * the procedure succeeds, the chip is considered to be present.
5546e677cafSmario.six@gdsys.cc *
5556e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5566e677cafSmario.six@gdsys.cc * @chip: The chip address to probe.
5576e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
5586e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5596e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
560306563a7SAlbert Aribaud */
__twsi_i2c_probe_chip(struct mvtwsi_registers * twsi,uchar chip,uint tick)561c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
562c68c6243Smario.six@gdsys.cc uint tick)
56301ec99d9SAlbert Aribaud {
564306563a7SAlbert Aribaud u8 dummy_byte;
565306563a7SAlbert Aribaud int status;
56601ec99d9SAlbert Aribaud
56749c801bfSmario.six@gdsys.cc /* Begin i2c read */
568c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
56949c801bfSmario.six@gdsys.cc /* Dummy read was accepted: receive byte, but NAK it. */
570306563a7SAlbert Aribaud if (status == 0)
571c68c6243Smario.six@gdsys.cc status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
572306563a7SAlbert Aribaud /* Stop transaction */
573c68c6243Smario.six@gdsys.cc twsi_stop(twsi, tick);
57449c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
575306563a7SAlbert Aribaud return status;
57601ec99d9SAlbert Aribaud }
57701ec99d9SAlbert Aribaud
578306563a7SAlbert Aribaud /*
5796e677cafSmario.six@gdsys.cc * __twsi_i2c_read() - Read data from a I2C chip.
5806e677cafSmario.six@gdsys.cc *
5816e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address
5826e677cafSmario.six@gdsys.cc * bytes; then begins a I2C read transaction, and receives the data bytes.
583306563a7SAlbert Aribaud *
58449c801bfSmario.six@gdsys.cc * NOTE: Some devices want a stop right before the second start, while some
58549c801bfSmario.six@gdsys.cc * will choke if it is there. Since deciding this is not yet supported in
58649c801bfSmario.six@gdsys.cc * higher level APIs, we need to make a decision here, and for the moment that
58749c801bfSmario.six@gdsys.cc * will be a repeated start without a preceding stop.
5886e677cafSmario.six@gdsys.cc *
5896e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
5906e677cafSmario.six@gdsys.cc * @chip: The chip address to read from.
5916e677cafSmario.six@gdsys.cc * @addr: The address bytes to send.
5926e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes.
5936e677cafSmario.six@gdsys.cc * @data: The buffer to receive the data read from the chip (has to have
5946e677cafSmario.six@gdsys.cc * a size of at least 'length' bytes).
5956e677cafSmario.six@gdsys.cc * @length: The amount of data to be read from the chip in bytes.
5966e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
5976e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
5986e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
599306563a7SAlbert Aribaud */
__twsi_i2c_read(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)6003c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
601c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length,
602c68c6243Smario.six@gdsys.cc uint tick)
60301ec99d9SAlbert Aribaud {
604059fce9fSmario.six@gdsys.cc int status = 0;
605059fce9fSmario.six@gdsys.cc int stop_status;
60624f9c6bbSmario.six@gdsys.cc int expected_start = MVTWSI_STATUS_START;
60701ec99d9SAlbert Aribaud
60824f9c6bbSmario.six@gdsys.cc if (alen > 0) {
60949c801bfSmario.six@gdsys.cc /* Begin i2c write to send the address bytes */
610c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1), tick);
61149c801bfSmario.six@gdsys.cc /* Send address bytes */
612306563a7SAlbert Aribaud while ((status == 0) && alen--)
61303d6cd97SStefan Roese status = twsi_send(twsi, addr[alen],
614c68c6243Smario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK, tick);
61524f9c6bbSmario.six@gdsys.cc /* Send repeated STARTs after the initial START */
61624f9c6bbSmario.six@gdsys.cc expected_start = MVTWSI_STATUS_REPEATED_START;
61724f9c6bbSmario.six@gdsys.cc }
61849c801bfSmario.six@gdsys.cc /* Begin i2c read to receive data bytes */
619306563a7SAlbert Aribaud if (status == 0)
620c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
621670514f5Smario.six@gdsys.cc /* Receive actual data bytes; set NAK if we if we have nothing more to
622670514f5Smario.six@gdsys.cc * read */
623670514f5Smario.six@gdsys.cc while ((status == 0) && length--)
6243c4db636Smario.six@gdsys.cc status = twsi_recv(twsi, data++,
625670514f5Smario.six@gdsys.cc length > 0 ?
626c68c6243Smario.six@gdsys.cc MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
627306563a7SAlbert Aribaud /* Stop transaction */
628c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick);
62949c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
630059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status;
63101ec99d9SAlbert Aribaud }
63201ec99d9SAlbert Aribaud
633306563a7SAlbert Aribaud /*
6346e677cafSmario.six@gdsys.cc * __twsi_i2c_write() - Send data to a I2C chip.
6356e677cafSmario.six@gdsys.cc *
6366e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address
6376e677cafSmario.six@gdsys.cc * bytes; then begins a new I2C write transaction, and sends the data bytes.
6386e677cafSmario.six@gdsys.cc *
6396e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use.
6406e677cafSmario.six@gdsys.cc * @chip: The chip address to read from.
6416e677cafSmario.six@gdsys.cc * @addr: The address bytes to send.
6426e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes.
6436e677cafSmario.six@gdsys.cc * @data: The buffer containing the data to be sent to the chip.
6446e677cafSmario.six@gdsys.cc * @length: The length of data to be sent to the chip in bytes.
6456e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed.
6466e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or
6476e677cafSmario.six@gdsys.cc * unexpected I2C status occurred.
648306563a7SAlbert Aribaud */
__twsi_i2c_write(struct mvtwsi_registers * twsi,uchar chip,u8 * addr,int alen,uchar * data,int length,uint tick)6493c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
650c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length,
651c68c6243Smario.six@gdsys.cc uint tick)
65201ec99d9SAlbert Aribaud {
653059fce9fSmario.six@gdsys.cc int status, stop_status;
65401ec99d9SAlbert Aribaud
65549c801bfSmario.six@gdsys.cc /* Begin i2c write to send first the address bytes, then the
65649c801bfSmario.six@gdsys.cc * data bytes */
657c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
65849c801bfSmario.six@gdsys.cc /* Send address bytes */
659f8a10ed1Smario.six@gdsys.cc while ((status == 0) && (alen-- > 0))
66003d6cd97SStefan Roese status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK,
661c68c6243Smario.six@gdsys.cc tick);
66249c801bfSmario.six@gdsys.cc /* Send data bytes */
663306563a7SAlbert Aribaud while ((status == 0) && (length-- > 0))
664c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
665c68c6243Smario.six@gdsys.cc tick);
666306563a7SAlbert Aribaud /* Stop transaction */
667c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick);
66849c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */
669059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status;
67001ec99d9SAlbert Aribaud }
67101ec99d9SAlbert Aribaud
67214a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C
twsi_i2c_init(struct i2c_adapter * adap,int speed,int slaveadd)67361bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
67461bc02b2Smario.six@gdsys.cc int slaveadd)
67561bc02b2Smario.six@gdsys.cc {
6763c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
677c68c6243Smario.six@gdsys.cc __twsi_i2c_init(twsi, speed, slaveadd, NULL);
67861bc02b2Smario.six@gdsys.cc }
67961bc02b2Smario.six@gdsys.cc
twsi_i2c_set_bus_speed(struct i2c_adapter * adap,uint requested_speed)68061bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
68161bc02b2Smario.six@gdsys.cc uint requested_speed)
68261bc02b2Smario.six@gdsys.cc {
6833c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
684c68c6243Smario.six@gdsys.cc __twsi_i2c_set_bus_speed(twsi, requested_speed);
685c68c6243Smario.six@gdsys.cc return 0;
68661bc02b2Smario.six@gdsys.cc }
68761bc02b2Smario.six@gdsys.cc
twsi_i2c_probe(struct i2c_adapter * adap,uchar chip)68861bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
68961bc02b2Smario.six@gdsys.cc {
6903c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
691c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(twsi, chip, 10000);
69261bc02b2Smario.six@gdsys.cc }
69361bc02b2Smario.six@gdsys.cc
twsi_i2c_read(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)69461bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
69561bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length)
69661bc02b2Smario.six@gdsys.cc {
6973c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
698f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4];
699f8a10ed1Smario.six@gdsys.cc
700f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF;
701f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF;
702f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF;
703f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF;
704f8a10ed1Smario.six@gdsys.cc
705c68c6243Smario.six@gdsys.cc return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
706c68c6243Smario.six@gdsys.cc 10000);
70761bc02b2Smario.six@gdsys.cc }
70861bc02b2Smario.six@gdsys.cc
twsi_i2c_write(struct i2c_adapter * adap,uchar chip,uint addr,int alen,uchar * data,int length)70961bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
71061bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length)
71161bc02b2Smario.six@gdsys.cc {
7123c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap);
713f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4];
714f8a10ed1Smario.six@gdsys.cc
715f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF;
716f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF;
717f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF;
718f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF;
719f8a10ed1Smario.six@gdsys.cc
720c68c6243Smario.six@gdsys.cc return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
721c68c6243Smario.six@gdsys.cc 10000);
72261bc02b2Smario.six@gdsys.cc }
72361bc02b2Smario.six@gdsys.cc
724dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0
7250db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
7260db2bbdcSHans de Goede twsi_i2c_read, twsi_i2c_write,
7270db2bbdcSHans de Goede twsi_i2c_set_bus_speed,
7280db2bbdcSHans de Goede CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
729dd82242bSPaul Kocialkowski #endif
730dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1
731dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, 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, 1)
735dd82242bSPaul Kocialkowski
736dd82242bSPaul Kocialkowski #endif
737dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2
738dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, 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, 2)
742dd82242bSPaul Kocialkowski
743dd82242bSPaul Kocialkowski #endif
744dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3
745dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, 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, 3)
749dd82242bSPaul Kocialkowski
750dd82242bSPaul Kocialkowski #endif
751dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4
752dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
753dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write,
754dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed,
755dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
756dd82242bSPaul Kocialkowski
757dd82242bSPaul Kocialkowski #endif
7589d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5
7599d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
7609d082687SJelle van der Waa twsi_i2c_read, twsi_i2c_write,
7619d082687SJelle van der Waa twsi_i2c_set_bus_speed,
7629d082687SJelle van der Waa CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
7639d082687SJelle van der Waa
7649d082687SJelle van der Waa #endif
76514a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */
76614a6ff2cSmario.six@gdsys.cc
76714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
76814a6ff2cSmario.six@gdsys.cc u32 chip_flags)
76914a6ff2cSmario.six@gdsys.cc {
77014a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
771c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
77214a6ff2cSmario.six@gdsys.cc }
77314a6ff2cSmario.six@gdsys.cc
77414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
77514a6ff2cSmario.six@gdsys.cc {
77614a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
777c68c6243Smario.six@gdsys.cc
778c68c6243Smario.six@gdsys.cc dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
779c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed);
780c68c6243Smario.six@gdsys.cc
781c68c6243Smario.six@gdsys.cc return 0;
78214a6ff2cSmario.six@gdsys.cc }
78314a6ff2cSmario.six@gdsys.cc
78414a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
78514a6ff2cSmario.six@gdsys.cc {
78614a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
78714a6ff2cSmario.six@gdsys.cc
788a821c4afSSimon Glass dev->base = devfdt_get_addr_ptr(bus);
78914a6ff2cSmario.six@gdsys.cc
79014a6ff2cSmario.six@gdsys.cc if (!dev->base)
79114a6ff2cSmario.six@gdsys.cc return -ENOMEM;
79214a6ff2cSmario.six@gdsys.cc
793e160f7d4SSimon Glass dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79414a6ff2cSmario.six@gdsys.cc "cell-index", -1);
795e160f7d4SSimon Glass dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79614a6ff2cSmario.six@gdsys.cc "u-boot,i2c-slave-addr", 0x0);
797e160f7d4SSimon Glass dev->speed = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
79814a6ff2cSmario.six@gdsys.cc "clock-frequency", 100000);
79914a6ff2cSmario.six@gdsys.cc return 0;
80014a6ff2cSmario.six@gdsys.cc }
80114a6ff2cSmario.six@gdsys.cc
802*173ec351SBaruch Siach static void twsi_disable_i2c_slave(struct mvtwsi_registers *twsi)
803*173ec351SBaruch Siach {
804*173ec351SBaruch Siach clrbits_le32(&twsi->debug, BIT(18));
805*173ec351SBaruch Siach }
806*173ec351SBaruch Siach
807*173ec351SBaruch Siach static int mvtwsi_i2c_bind(struct udevice *bus)
808*173ec351SBaruch Siach {
809*173ec351SBaruch Siach struct mvtwsi_registers *twsi = devfdt_get_addr_ptr(bus);
810*173ec351SBaruch Siach
811*173ec351SBaruch Siach /* Disable the hidden slave in i2c0 of these platforms */
812*173ec351SBaruch Siach if ((IS_ENABLED(CONFIG_ARMADA_38X) || IS_ENABLED(CONFIG_KIRKWOOD))
813*173ec351SBaruch Siach && bus->req_seq == 0)
814*173ec351SBaruch Siach twsi_disable_i2c_slave(twsi);
815*173ec351SBaruch Siach
816*173ec351SBaruch Siach return 0;
817*173ec351SBaruch Siach }
818*173ec351SBaruch Siach
81914a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus)
82014a6ff2cSmario.six@gdsys.cc {
82114a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
822c68c6243Smario.six@gdsys.cc uint actual_speed;
823c68c6243Smario.six@gdsys.cc
824c68c6243Smario.six@gdsys.cc __twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
825c68c6243Smario.six@gdsys.cc dev->speed = actual_speed;
826c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed);
82714a6ff2cSmario.six@gdsys.cc return 0;
82814a6ff2cSmario.six@gdsys.cc }
82914a6ff2cSmario.six@gdsys.cc
83014a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
83114a6ff2cSmario.six@gdsys.cc {
83214a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
83314a6ff2cSmario.six@gdsys.cc struct i2c_msg *dmsg, *omsg, dummy;
83414a6ff2cSmario.six@gdsys.cc
83514a6ff2cSmario.six@gdsys.cc memset(&dummy, 0, sizeof(struct i2c_msg));
83614a6ff2cSmario.six@gdsys.cc
83714a6ff2cSmario.six@gdsys.cc /* We expect either two messages (one with an offset and one with the
83814a6ff2cSmario.six@gdsys.cc * actual data) or one message (just data or offset/data combined) */
83914a6ff2cSmario.six@gdsys.cc if (nmsgs > 2 || nmsgs == 0) {
84014a6ff2cSmario.six@gdsys.cc debug("%s: Only one or two messages are supported.", __func__);
84114a6ff2cSmario.six@gdsys.cc return -1;
84214a6ff2cSmario.six@gdsys.cc }
84314a6ff2cSmario.six@gdsys.cc
84414a6ff2cSmario.six@gdsys.cc omsg = nmsgs == 1 ? &dummy : msg;
84514a6ff2cSmario.six@gdsys.cc dmsg = nmsgs == 1 ? msg : msg + 1;
84614a6ff2cSmario.six@gdsys.cc
84714a6ff2cSmario.six@gdsys.cc if (dmsg->flags & I2C_M_RD)
84814a6ff2cSmario.six@gdsys.cc return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
849c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len,
850c68c6243Smario.six@gdsys.cc dev->tick);
85114a6ff2cSmario.six@gdsys.cc else
85214a6ff2cSmario.six@gdsys.cc return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
853c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len,
854c68c6243Smario.six@gdsys.cc dev->tick);
85514a6ff2cSmario.six@gdsys.cc }
85614a6ff2cSmario.six@gdsys.cc
85714a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = {
85814a6ff2cSmario.six@gdsys.cc .xfer = mvtwsi_i2c_xfer,
85914a6ff2cSmario.six@gdsys.cc .probe_chip = mvtwsi_i2c_probe_chip,
86014a6ff2cSmario.six@gdsys.cc .set_bus_speed = mvtwsi_i2c_set_bus_speed,
86114a6ff2cSmario.six@gdsys.cc };
86214a6ff2cSmario.six@gdsys.cc
86314a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = {
86414a6ff2cSmario.six@gdsys.cc { .compatible = "marvell,mv64xxx-i2c", },
86587de0eb3SStefan Roese { .compatible = "marvell,mv78230-i2c", },
866a8f01ccfSJernej Skrabec { .compatible = "allwinner,sun6i-a31-i2c", },
86714a6ff2cSmario.six@gdsys.cc { /* sentinel */ }
86814a6ff2cSmario.six@gdsys.cc };
86914a6ff2cSmario.six@gdsys.cc
87014a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = {
87114a6ff2cSmario.six@gdsys.cc .name = "i2c_mvtwsi",
87214a6ff2cSmario.six@gdsys.cc .id = UCLASS_I2C,
87314a6ff2cSmario.six@gdsys.cc .of_match = mvtwsi_i2c_ids,
874*173ec351SBaruch Siach .bind = mvtwsi_i2c_bind,
87514a6ff2cSmario.six@gdsys.cc .probe = mvtwsi_i2c_probe,
87614a6ff2cSmario.six@gdsys.cc .ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
87714a6ff2cSmario.six@gdsys.cc .priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
87814a6ff2cSmario.six@gdsys.cc .ops = &mvtwsi_i2c_ops,
87914a6ff2cSmario.six@gdsys.cc };
88014a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */
881