xref: /rk3399_ARM-atf/drivers/nxp/i2c/i2c.c (revision 9719e19a977df3e8bf7567b3c0e1d6b2ebc5b46f)
1*c6d9fdbcSPankaj Gupta /*
2*c6d9fdbcSPankaj Gupta  * Copyright 2016-2020 NXP
3*c6d9fdbcSPankaj Gupta  *
4*c6d9fdbcSPankaj Gupta  * SPDX-License-Identifier: BSD-3-Clause
5*c6d9fdbcSPankaj Gupta  *
6*c6d9fdbcSPankaj Gupta  */
7*c6d9fdbcSPankaj Gupta 
8*c6d9fdbcSPankaj Gupta #include <errno.h>
9*c6d9fdbcSPankaj Gupta #include <stdint.h>
10*c6d9fdbcSPankaj Gupta #include <stdio.h>
11*c6d9fdbcSPankaj Gupta #include <stdlib.h>
12*c6d9fdbcSPankaj Gupta 
13*c6d9fdbcSPankaj Gupta #include <common/debug.h>
14*c6d9fdbcSPankaj Gupta #include <drivers/delay_timer.h>
15*c6d9fdbcSPankaj Gupta #include "i2c.h"
16*c6d9fdbcSPankaj Gupta #include <nxp_timer.h>
17*c6d9fdbcSPankaj Gupta 
18*c6d9fdbcSPankaj Gupta static uintptr_t g_nxp_i2c_addr;
19*c6d9fdbcSPankaj Gupta 
i2c_init(uintptr_t nxp_i2c_addr)20*c6d9fdbcSPankaj Gupta void i2c_init(uintptr_t nxp_i2c_addr)
21*c6d9fdbcSPankaj Gupta {
22*c6d9fdbcSPankaj Gupta 	struct ls_i2c *ccsr_i2c = (void *)nxp_i2c_addr;
23*c6d9fdbcSPankaj Gupta 
24*c6d9fdbcSPankaj Gupta 	g_nxp_i2c_addr = nxp_i2c_addr;
25*c6d9fdbcSPankaj Gupta 	/* Presume workaround for erratum a009203 applied */
26*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, I2C_CR_DIS);
27*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->fd, I2C_FD_CONSERV);
28*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->sr, I2C_SR_RST);
29*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, I2C_CR_EN);
30*c6d9fdbcSPankaj Gupta }
31*c6d9fdbcSPankaj Gupta 
wait_for_state(struct ls_i2c * ccsr_i2c,unsigned char state,unsigned char mask)32*c6d9fdbcSPankaj Gupta static int wait_for_state(struct ls_i2c *ccsr_i2c,
33*c6d9fdbcSPankaj Gupta 			  unsigned char state, unsigned char mask)
34*c6d9fdbcSPankaj Gupta {
35*c6d9fdbcSPankaj Gupta 	unsigned char sr;
36*c6d9fdbcSPankaj Gupta 	uint64_t start_time = get_timer_val(0);
37*c6d9fdbcSPankaj Gupta 	uint64_t timer;
38*c6d9fdbcSPankaj Gupta 
39*c6d9fdbcSPankaj Gupta 	do {
40*c6d9fdbcSPankaj Gupta 		sr = i2c_in(&ccsr_i2c->sr);
41*c6d9fdbcSPankaj Gupta 		if (sr & I2C_SR_AL) {
42*c6d9fdbcSPankaj Gupta 			i2c_out(&ccsr_i2c->sr, sr);
43*c6d9fdbcSPankaj Gupta 			WARN("I2C arbitration lost\n");
44*c6d9fdbcSPankaj Gupta 			return -EIO;
45*c6d9fdbcSPankaj Gupta 		}
46*c6d9fdbcSPankaj Gupta 		if ((sr & mask) == state) {
47*c6d9fdbcSPankaj Gupta 			return (int)sr;
48*c6d9fdbcSPankaj Gupta 		}
49*c6d9fdbcSPankaj Gupta 
50*c6d9fdbcSPankaj Gupta 		timer = get_timer_val(start_time);
51*c6d9fdbcSPankaj Gupta 		if (timer > I2C_TIMEOUT)
52*c6d9fdbcSPankaj Gupta 			break;
53*c6d9fdbcSPankaj Gupta 		mdelay(1);
54*c6d9fdbcSPankaj Gupta 	} while (1);
55*c6d9fdbcSPankaj Gupta 	WARN("I2C: Timeout waiting for state 0x%x, sr = 0x%x\n", state, sr);
56*c6d9fdbcSPankaj Gupta 
57*c6d9fdbcSPankaj Gupta 	return -ETIMEDOUT;
58*c6d9fdbcSPankaj Gupta }
59*c6d9fdbcSPankaj Gupta 
tx_byte(struct ls_i2c * ccsr_i2c,unsigned char c)60*c6d9fdbcSPankaj Gupta static int tx_byte(struct ls_i2c *ccsr_i2c, unsigned char c)
61*c6d9fdbcSPankaj Gupta {
62*c6d9fdbcSPankaj Gupta 	int ret;
63*c6d9fdbcSPankaj Gupta 
64*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
65*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->dr, c);
66*c6d9fdbcSPankaj Gupta 	ret = wait_for_state(ccsr_i2c, I2C_SR_IF, I2C_SR_IF);
67*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
68*c6d9fdbcSPankaj Gupta 		WARN("%s: state error\n", __func__);
69*c6d9fdbcSPankaj Gupta 		return ret;
70*c6d9fdbcSPankaj Gupta 	}
71*c6d9fdbcSPankaj Gupta 	if (ret & I2C_SR_RX_NAK) {
72*c6d9fdbcSPankaj Gupta 		WARN("%s: nodev\n", __func__);
73*c6d9fdbcSPankaj Gupta 		return -ENODEV;
74*c6d9fdbcSPankaj Gupta 	}
75*c6d9fdbcSPankaj Gupta 
76*c6d9fdbcSPankaj Gupta 	return 0;
77*c6d9fdbcSPankaj Gupta }
78*c6d9fdbcSPankaj Gupta 
gen_stop(struct ls_i2c * ccsr_i2c)79*c6d9fdbcSPankaj Gupta static int gen_stop(struct ls_i2c *ccsr_i2c)
80*c6d9fdbcSPankaj Gupta {
81*c6d9fdbcSPankaj Gupta 	unsigned char cr;
82*c6d9fdbcSPankaj Gupta 	int ret;
83*c6d9fdbcSPankaj Gupta 
84*c6d9fdbcSPankaj Gupta 	cr = i2c_in(&ccsr_i2c->cr);
85*c6d9fdbcSPankaj Gupta 	cr &= ~(I2C_CR_MA | I2C_CR_TX);
86*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, cr);
87*c6d9fdbcSPankaj Gupta 	ret = wait_for_state(ccsr_i2c, I2C_SR_IDLE, I2C_SR_BB);
88*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
89*c6d9fdbcSPankaj Gupta 		WARN("I2C: Generating stop failed.\n");
90*c6d9fdbcSPankaj Gupta 	}
91*c6d9fdbcSPankaj Gupta 	return ret;
92*c6d9fdbcSPankaj Gupta }
93*c6d9fdbcSPankaj Gupta 
i2c_write_addr(struct ls_i2c * ccsr_i2c,unsigned char chip,int addr,int alen)94*c6d9fdbcSPankaj Gupta static int i2c_write_addr(struct ls_i2c *ccsr_i2c, unsigned char chip,
95*c6d9fdbcSPankaj Gupta 			  int addr, int alen)
96*c6d9fdbcSPankaj Gupta {
97*c6d9fdbcSPankaj Gupta 	int ret;
98*c6d9fdbcSPankaj Gupta 	unsigned char cr;
99*c6d9fdbcSPankaj Gupta 
100*c6d9fdbcSPankaj Gupta 	if (alen != 1) {
101*c6d9fdbcSPankaj Gupta 		WARN("I2C: Unsupported address len [%d]\n", alen);
102*c6d9fdbcSPankaj Gupta 		return -EIO;
103*c6d9fdbcSPankaj Gupta 	}
104*c6d9fdbcSPankaj Gupta 
105*c6d9fdbcSPankaj Gupta 	if (i2c_in(&ccsr_i2c->ad) == (chip << 1)) {
106*c6d9fdbcSPankaj Gupta 		WARN("I2C: slave address same as self\n");
107*c6d9fdbcSPankaj Gupta 		return -ENODEV;
108*c6d9fdbcSPankaj Gupta 	}
109*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
110*c6d9fdbcSPankaj Gupta 	ret = wait_for_state(ccsr_i2c, I2C_SR_IDLE, I2C_SR_BB);
111*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
112*c6d9fdbcSPankaj Gupta 		return ret;
113*c6d9fdbcSPankaj Gupta 	}
114*c6d9fdbcSPankaj Gupta 
115*c6d9fdbcSPankaj Gupta 	cr = i2c_in(&ccsr_i2c->cr);
116*c6d9fdbcSPankaj Gupta 	cr |= I2C_CR_MA;
117*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, cr);
118*c6d9fdbcSPankaj Gupta 	ret = wait_for_state(ccsr_i2c, I2C_SR_BB, I2C_SR_BB);
119*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
120*c6d9fdbcSPankaj Gupta 		return ret;
121*c6d9fdbcSPankaj Gupta 	}
122*c6d9fdbcSPankaj Gupta 
123*c6d9fdbcSPankaj Gupta 	VERBOSE("Before writing chip %d\n", chip);
124*c6d9fdbcSPankaj Gupta 	cr |= I2C_CR_TX | I2C_CR_TX_NAK;
125*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, cr);
126*c6d9fdbcSPankaj Gupta 	ret = tx_byte(ccsr_i2c, chip << 1);
127*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
128*c6d9fdbcSPankaj Gupta 		gen_stop(ccsr_i2c);
129*c6d9fdbcSPankaj Gupta 		return ret;
130*c6d9fdbcSPankaj Gupta 	}
131*c6d9fdbcSPankaj Gupta 
132*c6d9fdbcSPankaj Gupta 	VERBOSE("Before writing addr\n");
133*c6d9fdbcSPankaj Gupta 	while (alen--) {
134*c6d9fdbcSPankaj Gupta 		ret = tx_byte(ccsr_i2c, (addr >> (alen << 3)) & 0xff);
135*c6d9fdbcSPankaj Gupta 		if (ret < 0) {
136*c6d9fdbcSPankaj Gupta 			gen_stop(ccsr_i2c);
137*c6d9fdbcSPankaj Gupta 			return ret;
138*c6d9fdbcSPankaj Gupta 		}
139*c6d9fdbcSPankaj Gupta 	}
140*c6d9fdbcSPankaj Gupta 
141*c6d9fdbcSPankaj Gupta 	return 0;
142*c6d9fdbcSPankaj Gupta }
143*c6d9fdbcSPankaj Gupta 
read_data(struct ls_i2c * ccsr_i2c,unsigned char chip,unsigned char * buf,int len)144*c6d9fdbcSPankaj Gupta static int read_data(struct ls_i2c *ccsr_i2c, unsigned char chip,
145*c6d9fdbcSPankaj Gupta 		     unsigned char *buf, int len)
146*c6d9fdbcSPankaj Gupta {
147*c6d9fdbcSPankaj Gupta 	int i;
148*c6d9fdbcSPankaj Gupta 	int ret;
149*c6d9fdbcSPankaj Gupta 	unsigned char cr;
150*c6d9fdbcSPankaj Gupta 
151*c6d9fdbcSPankaj Gupta 	cr = i2c_in(&ccsr_i2c->cr);
152*c6d9fdbcSPankaj Gupta 	cr &= ~(I2C_CR_TX | I2C_CR_TX_NAK);
153*c6d9fdbcSPankaj Gupta 	if (len == 1) {
154*c6d9fdbcSPankaj Gupta 		cr |= I2C_CR_TX_NAK;
155*c6d9fdbcSPankaj Gupta 	}
156*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, cr);
157*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
158*c6d9fdbcSPankaj Gupta 	i2c_in(&ccsr_i2c->dr);	/* dummy read */
159*c6d9fdbcSPankaj Gupta 	for (i = 0; i < len; i++) {
160*c6d9fdbcSPankaj Gupta 		ret = wait_for_state(ccsr_i2c, I2C_SR_IF, I2C_SR_IF);
161*c6d9fdbcSPankaj Gupta 		if (ret < 0) {
162*c6d9fdbcSPankaj Gupta 			gen_stop(ccsr_i2c);
163*c6d9fdbcSPankaj Gupta 			return ret;
164*c6d9fdbcSPankaj Gupta 		}
165*c6d9fdbcSPankaj Gupta 		if (i == (len - 1)) {
166*c6d9fdbcSPankaj Gupta 			gen_stop(ccsr_i2c);
167*c6d9fdbcSPankaj Gupta 		} else if (i == (len - 2)) {
168*c6d9fdbcSPankaj Gupta 			/* Updating the command to send
169*c6d9fdbcSPankaj Gupta 			 * No ACK.
170*c6d9fdbcSPankaj Gupta 			 */
171*c6d9fdbcSPankaj Gupta 			cr = i2c_in(&ccsr_i2c->cr);
172*c6d9fdbcSPankaj Gupta 			cr |= I2C_CR_TX_NAK;
173*c6d9fdbcSPankaj Gupta 			i2c_out(&ccsr_i2c->cr, cr);
174*c6d9fdbcSPankaj Gupta 		}
175*c6d9fdbcSPankaj Gupta 		i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
176*c6d9fdbcSPankaj Gupta 		buf[i] = i2c_in(&ccsr_i2c->dr);
177*c6d9fdbcSPankaj Gupta 	}
178*c6d9fdbcSPankaj Gupta 
179*c6d9fdbcSPankaj Gupta 	return 0;
180*c6d9fdbcSPankaj Gupta }
181*c6d9fdbcSPankaj Gupta 
write_data(struct ls_i2c * ccsr_i2c,unsigned char chip,const unsigned char * buf,int len)182*c6d9fdbcSPankaj Gupta static int write_data(struct ls_i2c *ccsr_i2c, unsigned char chip,
183*c6d9fdbcSPankaj Gupta 		      const unsigned char *buf, int len)
184*c6d9fdbcSPankaj Gupta {
185*c6d9fdbcSPankaj Gupta 	int i;
186*c6d9fdbcSPankaj Gupta 	int ret;
187*c6d9fdbcSPankaj Gupta 
188*c6d9fdbcSPankaj Gupta 	for (i = 0; i < len; i++) {
189*c6d9fdbcSPankaj Gupta 		ret = tx_byte(ccsr_i2c, buf[i]);
190*c6d9fdbcSPankaj Gupta 		if (ret < 0) {
191*c6d9fdbcSPankaj Gupta 			break;
192*c6d9fdbcSPankaj Gupta 		}
193*c6d9fdbcSPankaj Gupta 	}
194*c6d9fdbcSPankaj Gupta 	ret = gen_stop(ccsr_i2c);
195*c6d9fdbcSPankaj Gupta 
196*c6d9fdbcSPankaj Gupta 	return ret;
197*c6d9fdbcSPankaj Gupta }
198*c6d9fdbcSPankaj Gupta 
199*c6d9fdbcSPankaj Gupta 
i2c_read(unsigned char chip,int addr,int alen,unsigned char * buf,int len)200*c6d9fdbcSPankaj Gupta int i2c_read(unsigned char chip, int addr, int alen,
201*c6d9fdbcSPankaj Gupta 	     unsigned char *buf, int len)
202*c6d9fdbcSPankaj Gupta {
203*c6d9fdbcSPankaj Gupta 	int ret;
204*c6d9fdbcSPankaj Gupta 	unsigned char cr;
205*c6d9fdbcSPankaj Gupta 	struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
206*c6d9fdbcSPankaj Gupta 
207*c6d9fdbcSPankaj Gupta 	ret = i2c_write_addr(ccsr_i2c, chip, addr, alen);
208*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
209*c6d9fdbcSPankaj Gupta 		gen_stop(ccsr_i2c);
210*c6d9fdbcSPankaj Gupta 		return ret;
211*c6d9fdbcSPankaj Gupta 	}
212*c6d9fdbcSPankaj Gupta 
213*c6d9fdbcSPankaj Gupta 	cr = i2c_in(&ccsr_i2c->cr);
214*c6d9fdbcSPankaj Gupta 	cr |= I2C_CR_RSTA;
215*c6d9fdbcSPankaj Gupta 	i2c_out(&ccsr_i2c->cr, cr);
216*c6d9fdbcSPankaj Gupta 
217*c6d9fdbcSPankaj Gupta 	ret = tx_byte(ccsr_i2c, (chip << 1) | 1);
218*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
219*c6d9fdbcSPankaj Gupta 		gen_stop(ccsr_i2c);
220*c6d9fdbcSPankaj Gupta 		return ret;
221*c6d9fdbcSPankaj Gupta 	}
222*c6d9fdbcSPankaj Gupta 
223*c6d9fdbcSPankaj Gupta 	return read_data(ccsr_i2c, chip, buf, len);
224*c6d9fdbcSPankaj Gupta }
225*c6d9fdbcSPankaj Gupta 
i2c_write(unsigned char chip,int addr,int alen,const unsigned char * buf,int len)226*c6d9fdbcSPankaj Gupta int i2c_write(unsigned char chip, int addr, int alen,
227*c6d9fdbcSPankaj Gupta 	      const unsigned char *buf, int len)
228*c6d9fdbcSPankaj Gupta {
229*c6d9fdbcSPankaj Gupta 	int ret;
230*c6d9fdbcSPankaj Gupta 	struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
231*c6d9fdbcSPankaj Gupta 
232*c6d9fdbcSPankaj Gupta 	ret = i2c_write_addr(ccsr_i2c, chip, addr, alen);
233*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
234*c6d9fdbcSPankaj Gupta 		return ret;
235*c6d9fdbcSPankaj Gupta 	}
236*c6d9fdbcSPankaj Gupta 
237*c6d9fdbcSPankaj Gupta 	return write_data(ccsr_i2c, chip, buf, len);
238*c6d9fdbcSPankaj Gupta }
239*c6d9fdbcSPankaj Gupta 
i2c_probe_chip(unsigned char chip)240*c6d9fdbcSPankaj Gupta int i2c_probe_chip(unsigned char chip)
241*c6d9fdbcSPankaj Gupta {
242*c6d9fdbcSPankaj Gupta 	int ret;
243*c6d9fdbcSPankaj Gupta 	struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
244*c6d9fdbcSPankaj Gupta 
245*c6d9fdbcSPankaj Gupta 	ret = i2c_write_addr(ccsr_i2c, chip, 0, 0);
246*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
247*c6d9fdbcSPankaj Gupta 		WARN("write addr failed\n");
248*c6d9fdbcSPankaj Gupta 		return ret;
249*c6d9fdbcSPankaj Gupta 	}
250*c6d9fdbcSPankaj Gupta 
251*c6d9fdbcSPankaj Gupta 	ret = gen_stop(ccsr_i2c);
252*c6d9fdbcSPankaj Gupta 	if (ret < 0) {
253*c6d9fdbcSPankaj Gupta 		WARN("I2C: Probe not complete.\n");
254*c6d9fdbcSPankaj Gupta 	}
255*c6d9fdbcSPankaj Gupta 
256*c6d9fdbcSPankaj Gupta 	return ret;
257*c6d9fdbcSPankaj Gupta }
258