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