xref: /openbmc/u-boot/drivers/i2c/mxc_i2c.c (revision 30ea41a4)
1cdace066SSascha Hauer /*
2db84140bSMarek Vasut  * i2c driver for Freescale i.MX series
3cdace066SSascha Hauer  *
4cdace066SSascha Hauer  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
5db84140bSMarek Vasut  * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
6db84140bSMarek Vasut  *
7db84140bSMarek Vasut  * Based on i2c-imx.c from linux kernel:
8db84140bSMarek Vasut  *  Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de>
9db84140bSMarek Vasut  *  Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de>
10db84140bSMarek Vasut  *  Copyright (C) 2007 RightHand Technologies, Inc.
11db84140bSMarek Vasut  *  Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
12db84140bSMarek Vasut  *
13cdace066SSascha Hauer  *
14cdace066SSascha Hauer  * See file CREDITS for list of people who contributed to this
15cdace066SSascha Hauer  * project.
16cdace066SSascha Hauer  *
17cdace066SSascha Hauer  * This program is free software; you can redistribute it and/or
18cdace066SSascha Hauer  * modify it under the terms of the GNU General Public License as
19cdace066SSascha Hauer  * published by the Free Software Foundation; either version 2 of
20cdace066SSascha Hauer  * the License, or (at your option) any later version.
21cdace066SSascha Hauer  *
22cdace066SSascha Hauer  * This program is distributed in the hope that it will be useful,
23cdace066SSascha Hauer  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24cdace066SSascha Hauer  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25cdace066SSascha Hauer  * GNU General Public License for more details.
26cdace066SSascha Hauer  *
27cdace066SSascha Hauer  * You should have received a copy of the GNU General Public License
28cdace066SSascha Hauer  * along with this program; if not, write to the Free Software
29cdace066SSascha Hauer  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30cdace066SSascha Hauer  * MA 02111-1307 USA
31cdace066SSascha Hauer  */
32cdace066SSascha Hauer 
33cdace066SSascha Hauer #include <common.h>
34127cec18SLiu Hui-R64343 #include <asm/arch/clock.h>
3586271115SStefano Babic #include <asm/arch/imx-regs.h>
36cea60b0cSTroy Kisky #include <asm/errno.h>
3724cd738bSTroy Kisky #include <asm/io.h>
38bf0783dfSMarek Vasut #include <i2c.h>
397aa57a01STroy Kisky #include <watchdog.h>
40cdace066SSascha Hauer 
41*30ea41a4SAlison Wang #ifdef I2C_QUIRK_REG
42*30ea41a4SAlison Wang struct mxc_i2c_regs {
43*30ea41a4SAlison Wang 	uint8_t		iadr;
44*30ea41a4SAlison Wang 	uint8_t		ifdr;
45*30ea41a4SAlison Wang 	uint8_t		i2cr;
46*30ea41a4SAlison Wang 	uint8_t		i2sr;
47*30ea41a4SAlison Wang 	uint8_t		i2dr;
48*30ea41a4SAlison Wang };
49*30ea41a4SAlison Wang #else
50db84140bSMarek Vasut struct mxc_i2c_regs {
51db84140bSMarek Vasut 	uint32_t	iadr;
52db84140bSMarek Vasut 	uint32_t	ifdr;
53db84140bSMarek Vasut 	uint32_t	i2cr;
54db84140bSMarek Vasut 	uint32_t	i2sr;
55db84140bSMarek Vasut 	uint32_t	i2dr;
56db84140bSMarek Vasut };
57*30ea41a4SAlison Wang #endif
58cdace066SSascha Hauer 
59cdace066SSascha Hauer #define I2CR_IIEN	(1 << 6)
60cdace066SSascha Hauer #define I2CR_MSTA	(1 << 5)
61cdace066SSascha Hauer #define I2CR_MTX	(1 << 4)
62cdace066SSascha Hauer #define I2CR_TX_NO_AK	(1 << 3)
63cdace066SSascha Hauer #define I2CR_RSTA	(1 << 2)
64cdace066SSascha Hauer 
65cdace066SSascha Hauer #define I2SR_ICF	(1 << 7)
66cdace066SSascha Hauer #define I2SR_IBB	(1 << 5)
67d5383a63STroy Kisky #define I2SR_IAL	(1 << 4)
68cdace066SSascha Hauer #define I2SR_IIF	(1 << 1)
69cdace066SSascha Hauer #define I2SR_RX_NO_AK	(1 << 0)
70cdace066SSascha Hauer 
71*30ea41a4SAlison Wang #ifdef I2C_QUIRK_REG
72*30ea41a4SAlison Wang #define I2CR_IEN	(0 << 7)
73*30ea41a4SAlison Wang #define I2CR_IDIS	(1 << 7)
74*30ea41a4SAlison Wang #define I2SR_IIF_CLEAR	(1 << 1)
75*30ea41a4SAlison Wang #else
76*30ea41a4SAlison Wang #define I2CR_IEN	(1 << 7)
77*30ea41a4SAlison Wang #define I2CR_IDIS	(0 << 7)
78*30ea41a4SAlison Wang #define I2SR_IIF_CLEAR	(0 << 1)
79*30ea41a4SAlison Wang #endif
80*30ea41a4SAlison Wang 
81e4ff525fSTroy Kisky #if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE)
82de6f604dSTroy Kisky #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
83cdace066SSascha Hauer #endif
84cdace066SSascha Hauer 
85*30ea41a4SAlison Wang #ifdef I2C_QUIRK_REG
86*30ea41a4SAlison Wang static u16 i2c_clk_div[60][2] = {
87*30ea41a4SAlison Wang 	{ 20,	0x00 }, { 22,	0x01 }, { 24,	0x02 }, { 26,	0x03 },
88*30ea41a4SAlison Wang 	{ 28,	0x04 },	{ 30,	0x05 },	{ 32,	0x09 }, { 34,	0x06 },
89*30ea41a4SAlison Wang 	{ 36,	0x0A }, { 40,	0x07 }, { 44,	0x0C }, { 48,	0x0D },
90*30ea41a4SAlison Wang 	{ 52,	0x43 },	{ 56,	0x0E }, { 60,	0x45 }, { 64,	0x12 },
91*30ea41a4SAlison Wang 	{ 68,	0x0F },	{ 72,	0x13 },	{ 80,	0x14 },	{ 88,	0x15 },
92*30ea41a4SAlison Wang 	{ 96,	0x19 },	{ 104,	0x16 },	{ 112,	0x1A },	{ 128,	0x17 },
93*30ea41a4SAlison Wang 	{ 136,	0x4F }, { 144,	0x1C },	{ 160,	0x1D }, { 176,	0x55 },
94*30ea41a4SAlison Wang 	{ 192,	0x1E }, { 208,	0x56 },	{ 224,	0x22 }, { 228,	0x24 },
95*30ea41a4SAlison Wang 	{ 240,	0x1F },	{ 256,	0x23 }, { 288,	0x5C },	{ 320,	0x25 },
96*30ea41a4SAlison Wang 	{ 384,	0x26 }, { 448,	0x2A },	{ 480,	0x27 }, { 512,	0x2B },
97*30ea41a4SAlison Wang 	{ 576,	0x2C },	{ 640,	0x2D },	{ 768,	0x31 }, { 896,	0x32 },
98*30ea41a4SAlison Wang 	{ 960,	0x2F },	{ 1024,	0x33 },	{ 1152,	0x34 }, { 1280,	0x35 },
99*30ea41a4SAlison Wang 	{ 1536,	0x36 }, { 1792,	0x3A },	{ 1920,	0x37 },	{ 2048,	0x3B },
100*30ea41a4SAlison Wang 	{ 2304,	0x3C },	{ 2560,	0x3D },	{ 3072,	0x3E }, { 3584,	0x7A },
101*30ea41a4SAlison Wang 	{ 3840,	0x3F }, { 4096,	0x7B }, { 5120,	0x7D },	{ 6144,	0x7E },
102*30ea41a4SAlison Wang };
103*30ea41a4SAlison Wang #else
104db84140bSMarek Vasut static u16 i2c_clk_div[50][2] = {
105db84140bSMarek Vasut 	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
106db84140bSMarek Vasut 	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
107db84140bSMarek Vasut 	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
108db84140bSMarek Vasut 	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
109db84140bSMarek Vasut 	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
110db84140bSMarek Vasut 	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
111db84140bSMarek Vasut 	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
112db84140bSMarek Vasut 	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
113db84140bSMarek Vasut 	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
114db84140bSMarek Vasut 	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
115db84140bSMarek Vasut 	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
116db84140bSMarek Vasut 	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
117db84140bSMarek Vasut 	{ 3072,	0x1E }, { 3840,	0x1F }
118db84140bSMarek Vasut };
119*30ea41a4SAlison Wang #endif
120cdace066SSascha Hauer 
121db84140bSMarek Vasut /*
122db84140bSMarek Vasut  * Calculate and set proper clock divider
123db84140bSMarek Vasut  */
124bf0783dfSMarek Vasut static uint8_t i2c_imx_get_clk(unsigned int rate)
1251d549adeSStefano Babic {
126db84140bSMarek Vasut 	unsigned int i2c_clk_rate;
127db84140bSMarek Vasut 	unsigned int div;
128bf0783dfSMarek Vasut 	u8 clk_div;
129cdace066SSascha Hauer 
130127cec18SLiu Hui-R64343 #if defined(CONFIG_MX31)
1311d549adeSStefano Babic 	struct clock_control_regs *sc_regs =
1321d549adeSStefano Babic 		(struct clock_control_regs *)CCM_BASE;
133db84140bSMarek Vasut 
134e7de18afSGuennadi Liakhovetski 	/* start the required I2C clock */
135de6f604dSTroy Kisky 	writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET),
1361d549adeSStefano Babic 		&sc_regs->cgr0);
137127cec18SLiu Hui-R64343 #endif
138e7de18afSGuennadi Liakhovetski 
139db84140bSMarek Vasut 	/* Divider value calculation */
140e7bed5c2SMatthias Weisser 	i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK);
141db84140bSMarek Vasut 	div = (i2c_clk_rate + rate - 1) / rate;
142db84140bSMarek Vasut 	if (div < i2c_clk_div[0][0])
143b567b8ffSMarek Vasut 		clk_div = 0;
144db84140bSMarek Vasut 	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
145b567b8ffSMarek Vasut 		clk_div = ARRAY_SIZE(i2c_clk_div) - 1;
146db84140bSMarek Vasut 	else
147b567b8ffSMarek Vasut 		for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++)
148db84140bSMarek Vasut 			;
149cdace066SSascha Hauer 
150db84140bSMarek Vasut 	/* Store divider value */
151bf0783dfSMarek Vasut 	return clk_div;
152db84140bSMarek Vasut }
153cdace066SSascha Hauer 
154db84140bSMarek Vasut /*
155e4ff525fSTroy Kisky  * Set I2C Bus speed
156db84140bSMarek Vasut  */
1577f86bd57SMarek Vasut static int bus_i2c_set_bus_speed(void *base, int speed)
158db84140bSMarek Vasut {
159e4ff525fSTroy Kisky 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
160bf0783dfSMarek Vasut 	u8 clk_idx = i2c_imx_get_clk(speed);
161bf0783dfSMarek Vasut 	u8 idx = i2c_clk_div[clk_idx][1];
162bf0783dfSMarek Vasut 
163bf0783dfSMarek Vasut 	/* Store divider value */
164bf0783dfSMarek Vasut 	writeb(idx, &i2c_regs->ifdr);
165bf0783dfSMarek Vasut 
16683a1a190STroy Kisky 	/* Reset module */
167*30ea41a4SAlison Wang 	writeb(I2CR_IDIS, &i2c_regs->i2cr);
16883a1a190STroy Kisky 	writeb(0, &i2c_regs->i2sr);
169b567b8ffSMarek Vasut 	return 0;
170b567b8ffSMarek Vasut }
171b567b8ffSMarek Vasut 
172b567b8ffSMarek Vasut /*
173b567b8ffSMarek Vasut  * Get I2C Speed
174b567b8ffSMarek Vasut  */
1757f86bd57SMarek Vasut static unsigned int bus_i2c_get_bus_speed(void *base)
176b567b8ffSMarek Vasut {
177e4ff525fSTroy Kisky 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
178bf0783dfSMarek Vasut 	u8 clk_idx = readb(&i2c_regs->ifdr);
179bf0783dfSMarek Vasut 	u8 clk_div;
180bf0783dfSMarek Vasut 
181bf0783dfSMarek Vasut 	for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++)
182bf0783dfSMarek Vasut 		;
183bf0783dfSMarek Vasut 
184e7bed5c2SMatthias Weisser 	return mxc_get_clock(MXC_I2C_CLK) / i2c_clk_div[clk_div][0];
185b567b8ffSMarek Vasut }
186b567b8ffSMarek Vasut 
1877aa57a01STroy Kisky #define ST_BUS_IDLE (0 | (I2SR_IBB << 8))
1887aa57a01STroy Kisky #define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8))
1897aa57a01STroy Kisky #define ST_IIF (I2SR_IIF | (I2SR_IIF << 8))
1907aa57a01STroy Kisky 
1917aa57a01STroy Kisky static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state)
19281687212SStefano Babic {
1937aa57a01STroy Kisky 	unsigned sr;
1947aa57a01STroy Kisky 	ulong elapsed;
1957aa57a01STroy Kisky 	ulong start_time = get_timer(0);
1967aa57a01STroy Kisky 	for (;;) {
1977aa57a01STroy Kisky 		sr = readb(&i2c_regs->i2sr);
198d5383a63STroy Kisky 		if (sr & I2SR_IAL) {
199*30ea41a4SAlison Wang #ifdef I2C_QUIRK_REG
200*30ea41a4SAlison Wang 			writeb(sr | I2SR_IAL, &i2c_regs->i2sr);
201*30ea41a4SAlison Wang #else
202d5383a63STroy Kisky 			writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr);
203*30ea41a4SAlison Wang #endif
204d5383a63STroy Kisky 			printf("%s: Arbitration lost sr=%x cr=%x state=%x\n",
205d5383a63STroy Kisky 				__func__, sr, readb(&i2c_regs->i2cr), state);
206d5383a63STroy Kisky 			return -ERESTART;
207d5383a63STroy Kisky 		}
2087aa57a01STroy Kisky 		if ((sr & (state >> 8)) == (unsigned char)state)
2097aa57a01STroy Kisky 			return sr;
2107aa57a01STroy Kisky 		WATCHDOG_RESET();
2117aa57a01STroy Kisky 		elapsed = get_timer(start_time);
2127aa57a01STroy Kisky 		if (elapsed > (CONFIG_SYS_HZ / 10))	/* .1 seconds */
2137aa57a01STroy Kisky 			break;
21481687212SStefano Babic 	}
2157aa57a01STroy Kisky 	printf("%s: failed sr=%x cr=%x state=%x\n", __func__,
2167aa57a01STroy Kisky 			sr, readb(&i2c_regs->i2cr), state);
217cea60b0cSTroy Kisky 	return -ETIMEDOUT;
218db84140bSMarek Vasut }
219db84140bSMarek Vasut 
220cea60b0cSTroy Kisky static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte)
221cdace066SSascha Hauer {
222cea60b0cSTroy Kisky 	int ret;
223db84140bSMarek Vasut 
224*30ea41a4SAlison Wang 	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
225cea60b0cSTroy Kisky 	writeb(byte, &i2c_regs->i2dr);
2267aa57a01STroy Kisky 	ret = wait_for_sr_state(i2c_regs, ST_IIF);
227cea60b0cSTroy Kisky 	if (ret < 0)
228cea60b0cSTroy Kisky 		return ret;
229cea60b0cSTroy Kisky 	if (ret & I2SR_RX_NO_AK)
230cea60b0cSTroy Kisky 		return -ENODEV;
231cea60b0cSTroy Kisky 	return 0;
232db84140bSMarek Vasut }
233db84140bSMarek Vasut 
234db84140bSMarek Vasut /*
23590a5b70fSTroy Kisky  * Stop I2C transaction
236db84140bSMarek Vasut  */
23727a5da02STroy Kisky static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs)
238db84140bSMarek Vasut {
2397aa57a01STroy Kisky 	int ret;
24090a5b70fSTroy Kisky 	unsigned int temp = readb(&i2c_regs->i2cr);
241db84140bSMarek Vasut 
2421c076dbaSTroy Kisky 	temp &= ~(I2CR_MSTA | I2CR_MTX);
243db84140bSMarek Vasut 	writeb(temp, &i2c_regs->i2cr);
2447aa57a01STroy Kisky 	ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE);
2457aa57a01STroy Kisky 	if (ret < 0)
2467aa57a01STroy Kisky 		printf("%s:trigger stop failed\n", __func__);
247db84140bSMarek Vasut }
248db84140bSMarek Vasut 
249db84140bSMarek Vasut /*
250b230ddc2STroy Kisky  * Send start signal, chip address and
251b230ddc2STroy Kisky  * write register address
252db84140bSMarek Vasut  */
253a7f1a005STroy Kisky static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs,
254b230ddc2STroy Kisky 		uchar chip, uint addr, int alen)
255cdace066SSascha Hauer {
25671e9f3cbSTroy Kisky 	unsigned int temp;
25771e9f3cbSTroy Kisky 	int ret;
25871e9f3cbSTroy Kisky 
25971e9f3cbSTroy Kisky 	/* Enable I2C controller */
260*30ea41a4SAlison Wang #ifdef I2C_QUIRK_REG
261*30ea41a4SAlison Wang 	if (readb(&i2c_regs->i2cr) & I2CR_IDIS) {
262*30ea41a4SAlison Wang #else
26390a5b70fSTroy Kisky 	if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) {
264*30ea41a4SAlison Wang #endif
26571e9f3cbSTroy Kisky 		writeb(I2CR_IEN, &i2c_regs->i2cr);
26671e9f3cbSTroy Kisky 		/* Wait for controller to be stable */
26771e9f3cbSTroy Kisky 		udelay(50);
26890a5b70fSTroy Kisky 	}
269ca741da1STroy Kisky 	if (readb(&i2c_regs->iadr) == (chip << 1))
270ca741da1STroy Kisky 		writeb((chip << 1) ^ 2, &i2c_regs->iadr);
271*30ea41a4SAlison Wang 	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
27290a5b70fSTroy Kisky 	ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE);
27390a5b70fSTroy Kisky 	if (ret < 0)
274a7f1a005STroy Kisky 		return ret;
27571e9f3cbSTroy Kisky 
27671e9f3cbSTroy Kisky 	/* Start I2C transaction */
27771e9f3cbSTroy Kisky 	temp = readb(&i2c_regs->i2cr);
27871e9f3cbSTroy Kisky 	temp |= I2CR_MSTA;
27971e9f3cbSTroy Kisky 	writeb(temp, &i2c_regs->i2cr);
28071e9f3cbSTroy Kisky 
28171e9f3cbSTroy Kisky 	ret = wait_for_sr_state(i2c_regs, ST_BUS_BUSY);
28271e9f3cbSTroy Kisky 	if (ret < 0)
283a7f1a005STroy Kisky 		return ret;
284b230ddc2STroy Kisky 
28571e9f3cbSTroy Kisky 	temp |= I2CR_MTX | I2CR_TX_NO_AK;
28671e9f3cbSTroy Kisky 	writeb(temp, &i2c_regs->i2cr);
28771e9f3cbSTroy Kisky 
288b230ddc2STroy Kisky 	/* write slave address */
289b230ddc2STroy Kisky 	ret = tx_byte(i2c_regs, chip << 1);
290b230ddc2STroy Kisky 	if (ret < 0)
291a7f1a005STroy Kisky 		return ret;
292db84140bSMarek Vasut 
293bf0783dfSMarek Vasut 	while (alen--) {
294cea60b0cSTroy Kisky 		ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff);
295cea60b0cSTroy Kisky 		if (ret < 0)
296a7f1a005STroy Kisky 			return ret;
29781687212SStefano Babic 	}
298b230ddc2STroy Kisky 	return 0;
299a7f1a005STroy Kisky }
300a7f1a005STroy Kisky 
30196c19bd3STroy Kisky static int i2c_idle_bus(void *base);
30296c19bd3STroy Kisky 
303a7f1a005STroy Kisky static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs,
304a7f1a005STroy Kisky 		uchar chip, uint addr, int alen)
305a7f1a005STroy Kisky {
306a7f1a005STroy Kisky 	int retry;
307a7f1a005STroy Kisky 	int ret;
308a7f1a005STroy Kisky 	for (retry = 0; retry < 3; retry++) {
309a7f1a005STroy Kisky 		ret = i2c_init_transfer_(i2c_regs, chip, addr, alen);
310a7f1a005STroy Kisky 		if (ret >= 0)
311a7f1a005STroy Kisky 			return 0;
31227a5da02STroy Kisky 		i2c_imx_stop(i2c_regs);
313a7f1a005STroy Kisky 		if (ret == -ENODEV)
314a7f1a005STroy Kisky 			return ret;
315a7f1a005STroy Kisky 
316a7f1a005STroy Kisky 		printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip,
317a7f1a005STroy Kisky 				retry);
318a7f1a005STroy Kisky 		if (ret != -ERESTART)
319*30ea41a4SAlison Wang 			/* Disable controller */
320*30ea41a4SAlison Wang 			writeb(I2CR_IDIS, &i2c_regs->i2cr);
321a7f1a005STroy Kisky 		udelay(100);
32296c19bd3STroy Kisky 		if (i2c_idle_bus(i2c_regs) < 0)
32396c19bd3STroy Kisky 			break;
324a7f1a005STroy Kisky 	}
325a7f1a005STroy Kisky 	printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs);
326db84140bSMarek Vasut 	return ret;
327cdace066SSascha Hauer }
328cdace066SSascha Hauer 
329db84140bSMarek Vasut /*
330db84140bSMarek Vasut  * Read data from I2C device
331db84140bSMarek Vasut  */
332e4ff525fSTroy Kisky int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
333e4ff525fSTroy Kisky 		int len)
334db84140bSMarek Vasut {
335db84140bSMarek Vasut 	int ret;
336db84140bSMarek Vasut 	unsigned int temp;
337db84140bSMarek Vasut 	int i;
338e4ff525fSTroy Kisky 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
339cdace066SSascha Hauer 
340b230ddc2STroy Kisky 	ret = i2c_init_transfer(i2c_regs, chip, addr, alen);
341cea60b0cSTroy Kisky 	if (ret < 0)
342db84140bSMarek Vasut 		return ret;
343cdace066SSascha Hauer 
344db84140bSMarek Vasut 	temp = readb(&i2c_regs->i2cr);
345db84140bSMarek Vasut 	temp |= I2CR_RSTA;
346db84140bSMarek Vasut 	writeb(temp, &i2c_regs->i2cr);
347db84140bSMarek Vasut 
348cea60b0cSTroy Kisky 	ret = tx_byte(i2c_regs, (chip << 1) | 1);
349c4330d28STroy Kisky 	if (ret < 0) {
35027a5da02STroy Kisky 		i2c_imx_stop(i2c_regs);
351db84140bSMarek Vasut 		return ret;
352c4330d28STroy Kisky 	}
353db84140bSMarek Vasut 
354db84140bSMarek Vasut 	/* setup bus to read data */
355db84140bSMarek Vasut 	temp = readb(&i2c_regs->i2cr);
356db84140bSMarek Vasut 	temp &= ~(I2CR_MTX | I2CR_TX_NO_AK);
357db84140bSMarek Vasut 	if (len == 1)
358db84140bSMarek Vasut 		temp |= I2CR_TX_NO_AK;
359db84140bSMarek Vasut 	writeb(temp, &i2c_regs->i2cr);
360*30ea41a4SAlison Wang 	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
361ea572d85STroy Kisky 	readb(&i2c_regs->i2dr);		/* dummy read to clear ICF */
362db84140bSMarek Vasut 
363db84140bSMarek Vasut 	/* read data */
364db84140bSMarek Vasut 	for (i = 0; i < len; i++) {
3657aa57a01STroy Kisky 		ret = wait_for_sr_state(i2c_regs, ST_IIF);
3667aa57a01STroy Kisky 		if (ret < 0) {
36727a5da02STroy Kisky 			i2c_imx_stop(i2c_regs);
368db84140bSMarek Vasut 			return ret;
369c4330d28STroy Kisky 		}
370db84140bSMarek Vasut 
371db84140bSMarek Vasut 		/*
372db84140bSMarek Vasut 		 * It must generate STOP before read I2DR to prevent
373db84140bSMarek Vasut 		 * controller from generating another clock cycle
374db84140bSMarek Vasut 		 */
375db84140bSMarek Vasut 		if (i == (len - 1)) {
37627a5da02STroy Kisky 			i2c_imx_stop(i2c_regs);
377db84140bSMarek Vasut 		} else if (i == (len - 2)) {
378db84140bSMarek Vasut 			temp = readb(&i2c_regs->i2cr);
379db84140bSMarek Vasut 			temp |= I2CR_TX_NO_AK;
380db84140bSMarek Vasut 			writeb(temp, &i2c_regs->i2cr);
381cdace066SSascha Hauer 		}
382*30ea41a4SAlison Wang 		writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
383db84140bSMarek Vasut 		buf[i] = readb(&i2c_regs->i2dr);
384cdace066SSascha Hauer 	}
38527a5da02STroy Kisky 	i2c_imx_stop(i2c_regs);
3867aa57a01STroy Kisky 	return 0;
387db84140bSMarek Vasut }
388db84140bSMarek Vasut 
389db84140bSMarek Vasut /*
390db84140bSMarek Vasut  * Write data to I2C device
391db84140bSMarek Vasut  */
392e4ff525fSTroy Kisky int bus_i2c_write(void *base, uchar chip, uint addr, int alen,
393e4ff525fSTroy Kisky 		const uchar *buf, int len)
394cdace066SSascha Hauer {
395db84140bSMarek Vasut 	int ret;
396db84140bSMarek Vasut 	int i;
397e4ff525fSTroy Kisky 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
398cdace066SSascha Hauer 
399b230ddc2STroy Kisky 	ret = i2c_init_transfer(i2c_regs, chip, addr, alen);
400cea60b0cSTroy Kisky 	if (ret < 0)
401db84140bSMarek Vasut 		return ret;
402cdace066SSascha Hauer 
403db84140bSMarek Vasut 	for (i = 0; i < len; i++) {
404cea60b0cSTroy Kisky 		ret = tx_byte(i2c_regs, buf[i]);
405cea60b0cSTroy Kisky 		if (ret < 0)
406c4330d28STroy Kisky 			break;
407cdace066SSascha Hauer 	}
40827a5da02STroy Kisky 	i2c_imx_stop(i2c_regs);
409db84140bSMarek Vasut 	return ret;
410db84140bSMarek Vasut }
411cfbb88d3STroy Kisky 
412e4ff525fSTroy Kisky struct i2c_parms {
413e4ff525fSTroy Kisky 	void *base;
414e4ff525fSTroy Kisky 	void *idle_bus_data;
415e4ff525fSTroy Kisky 	int (*idle_bus_fn)(void *p);
416e4ff525fSTroy Kisky };
417e4ff525fSTroy Kisky 
418e4ff525fSTroy Kisky struct sram_data {
419e4ff525fSTroy Kisky 	unsigned curr_i2c_bus;
420e4ff525fSTroy Kisky 	struct i2c_parms i2c_data[3];
421e4ff525fSTroy Kisky };
422e4ff525fSTroy Kisky 
423e4ff525fSTroy Kisky /*
424e4ff525fSTroy Kisky  * For SPL boot some boards need i2c before SDRAM is initialized so force
425e4ff525fSTroy Kisky  * variables to live in SRAM
426e4ff525fSTroy Kisky  */
427e4ff525fSTroy Kisky static struct sram_data __attribute__((section(".data"))) srdata;
428e4ff525fSTroy Kisky 
429e4ff525fSTroy Kisky void *get_base(void)
430e4ff525fSTroy Kisky {
431e4ff525fSTroy Kisky #ifdef CONFIG_SYS_I2C_BASE
432e4ff525fSTroy Kisky #ifdef CONFIG_I2C_MULTI_BUS
433e4ff525fSTroy Kisky 	void *ret = srdata.i2c_data[srdata.curr_i2c_bus].base;
434e4ff525fSTroy Kisky 	if (ret)
435e4ff525fSTroy Kisky 		return ret;
436e4ff525fSTroy Kisky #endif
437e4ff525fSTroy Kisky 	return (void *)CONFIG_SYS_I2C_BASE;
438e4ff525fSTroy Kisky #elif defined(CONFIG_I2C_MULTI_BUS)
439e4ff525fSTroy Kisky 	return srdata.i2c_data[srdata.curr_i2c_bus].base;
440e4ff525fSTroy Kisky #else
441e4ff525fSTroy Kisky 	return srdata.i2c_data[0].base;
442e4ff525fSTroy Kisky #endif
443e4ff525fSTroy Kisky }
444e4ff525fSTroy Kisky 
44596c19bd3STroy Kisky static struct i2c_parms *i2c_get_parms(void *base)
44696c19bd3STroy Kisky {
44796c19bd3STroy Kisky 	int i = 0;
44896c19bd3STroy Kisky 	struct i2c_parms *p = srdata.i2c_data;
44996c19bd3STroy Kisky 	while (i < ARRAY_SIZE(srdata.i2c_data)) {
45096c19bd3STroy Kisky 		if (p->base == base)
45196c19bd3STroy Kisky 			return p;
45296c19bd3STroy Kisky 		p++;
45396c19bd3STroy Kisky 		i++;
45496c19bd3STroy Kisky 	}
45596c19bd3STroy Kisky 	printf("Invalid I2C base: %p\n", base);
45696c19bd3STroy Kisky 	return NULL;
45796c19bd3STroy Kisky }
45896c19bd3STroy Kisky 
45996c19bd3STroy Kisky static int i2c_idle_bus(void *base)
46096c19bd3STroy Kisky {
46196c19bd3STroy Kisky 	struct i2c_parms *p = i2c_get_parms(base);
46296c19bd3STroy Kisky 	if (p && p->idle_bus_fn)
46396c19bd3STroy Kisky 		return p->idle_bus_fn(p->idle_bus_data);
46496c19bd3STroy Kisky 	return 0;
46596c19bd3STroy Kisky }
46696c19bd3STroy Kisky 
4679815326dSTroy Kisky #ifdef CONFIG_I2C_MULTI_BUS
4689815326dSTroy Kisky unsigned int i2c_get_bus_num(void)
4699815326dSTroy Kisky {
4709815326dSTroy Kisky 	return srdata.curr_i2c_bus;
4719815326dSTroy Kisky }
4729815326dSTroy Kisky 
4739815326dSTroy Kisky int i2c_set_bus_num(unsigned bus_idx)
4749815326dSTroy Kisky {
4759815326dSTroy Kisky 	if (bus_idx >= ARRAY_SIZE(srdata.i2c_data))
4769815326dSTroy Kisky 		return -1;
4779815326dSTroy Kisky 	if (!srdata.i2c_data[bus_idx].base)
4789815326dSTroy Kisky 		return -1;
4799815326dSTroy Kisky 	srdata.curr_i2c_bus = bus_idx;
4809815326dSTroy Kisky 	return 0;
4819815326dSTroy Kisky }
4829815326dSTroy Kisky #endif
4839815326dSTroy Kisky 
484e4ff525fSTroy Kisky int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
485e4ff525fSTroy Kisky {
486e4ff525fSTroy Kisky 	return bus_i2c_read(get_base(), chip, addr, alen, buf, len);
487e4ff525fSTroy Kisky }
488e4ff525fSTroy Kisky 
489e4ff525fSTroy Kisky int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
490e4ff525fSTroy Kisky {
491e4ff525fSTroy Kisky 	return bus_i2c_write(get_base(), chip, addr, alen, buf, len);
492e4ff525fSTroy Kisky }
493e4ff525fSTroy Kisky 
494cfbb88d3STroy Kisky /*
495cfbb88d3STroy Kisky  * Test if a chip at a given address responds (probe the chip)
496cfbb88d3STroy Kisky  */
497cfbb88d3STroy Kisky int i2c_probe(uchar chip)
498cfbb88d3STroy Kisky {
499e4ff525fSTroy Kisky 	return bus_i2c_write(get_base(), chip, 0, 0, NULL, 0);
500e4ff525fSTroy Kisky }
501e4ff525fSTroy Kisky 
502e4ff525fSTroy Kisky void bus_i2c_init(void *base, int speed, int unused,
503e4ff525fSTroy Kisky 		int (*idle_bus_fn)(void *p), void *idle_bus_data)
504e4ff525fSTroy Kisky {
505e4ff525fSTroy Kisky 	int i = 0;
506e4ff525fSTroy Kisky 	struct i2c_parms *p = srdata.i2c_data;
507e4ff525fSTroy Kisky 	if (!base)
508e4ff525fSTroy Kisky 		return;
509e4ff525fSTroy Kisky 	for (;;) {
510e4ff525fSTroy Kisky 		if (!p->base || (p->base == base)) {
511e4ff525fSTroy Kisky 			p->base = base;
512e4ff525fSTroy Kisky 			if (idle_bus_fn) {
513e4ff525fSTroy Kisky 				p->idle_bus_fn = idle_bus_fn;
514e4ff525fSTroy Kisky 				p->idle_bus_data = idle_bus_data;
515e4ff525fSTroy Kisky 			}
516e4ff525fSTroy Kisky 			break;
517e4ff525fSTroy Kisky 		}
518e4ff525fSTroy Kisky 		p++;
519e4ff525fSTroy Kisky 		i++;
520e4ff525fSTroy Kisky 		if (i >= ARRAY_SIZE(srdata.i2c_data))
521e4ff525fSTroy Kisky 			return;
522e4ff525fSTroy Kisky 	}
523e4ff525fSTroy Kisky 	bus_i2c_set_bus_speed(base, speed);
524e4ff525fSTroy Kisky }
525e4ff525fSTroy Kisky 
526e4ff525fSTroy Kisky /*
527e4ff525fSTroy Kisky  * Init I2C Bus
528e4ff525fSTroy Kisky  */
529e4ff525fSTroy Kisky void i2c_init(int speed, int unused)
530e4ff525fSTroy Kisky {
531e4ff525fSTroy Kisky 	bus_i2c_init(get_base(), speed, unused, NULL, NULL);
532e4ff525fSTroy Kisky }
533e4ff525fSTroy Kisky 
534e4ff525fSTroy Kisky /*
535e4ff525fSTroy Kisky  * Set I2C Speed
536e4ff525fSTroy Kisky  */
537e4ff525fSTroy Kisky int i2c_set_bus_speed(unsigned int speed)
538e4ff525fSTroy Kisky {
539e4ff525fSTroy Kisky 	return bus_i2c_set_bus_speed(get_base(), speed);
540e4ff525fSTroy Kisky }
541e4ff525fSTroy Kisky 
542e4ff525fSTroy Kisky /*
543e4ff525fSTroy Kisky  * Get I2C Speed
544e4ff525fSTroy Kisky  */
545e4ff525fSTroy Kisky unsigned int i2c_get_bus_speed(void)
546e4ff525fSTroy Kisky {
547e4ff525fSTroy Kisky 	return bus_i2c_get_bus_speed(get_base());
548cfbb88d3STroy Kisky }
549