xref: /optee_os/core/drivers/imx_i2c.c (revision 78b3ea9c917074b0a61eca94106a09ffbaa3e904)
1*78b3ea9cSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
2*78b3ea9cSJorge Ramirez-Ortiz /*
3*78b3ea9cSJorge Ramirez-Ortiz  * (c) 2020 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd.
4*78b3ea9cSJorge Ramirez-Ortiz  */
5*78b3ea9cSJorge Ramirez-Ortiz #include <arm.h>
6*78b3ea9cSJorge Ramirez-Ortiz #include <drivers/imx_i2c.h>
7*78b3ea9cSJorge Ramirez-Ortiz #include <initcall.h>
8*78b3ea9cSJorge Ramirez-Ortiz #include <io.h>
9*78b3ea9cSJorge Ramirez-Ortiz #include <kernel/delay.h>
10*78b3ea9cSJorge Ramirez-Ortiz #include <mm/core_memprot.h>
11*78b3ea9cSJorge Ramirez-Ortiz #include <mm/core_mmu.h>
12*78b3ea9cSJorge Ramirez-Ortiz #include <platform_config.h>
13*78b3ea9cSJorge Ramirez-Ortiz #include <stdlib.h>
14*78b3ea9cSJorge Ramirez-Ortiz #include <trace.h>
15*78b3ea9cSJorge Ramirez-Ortiz #include <util.h>
16*78b3ea9cSJorge Ramirez-Ortiz 
17*78b3ea9cSJorge Ramirez-Ortiz #define I2C_CLK_RATE	24000000 /* Bits per second */
18*78b3ea9cSJorge Ramirez-Ortiz 
19*78b3ea9cSJorge Ramirez-Ortiz static struct io_pa_va i2c_bus[] = {
20*78b3ea9cSJorge Ramirez-Ortiz 	{ .pa = I2C1_BASE, },
21*78b3ea9cSJorge Ramirez-Ortiz 	{ .pa = I2C2_BASE, },
22*78b3ea9cSJorge Ramirez-Ortiz 	{ .pa = I2C3_BASE, },
23*78b3ea9cSJorge Ramirez-Ortiz };
24*78b3ea9cSJorge Ramirez-Ortiz 
25*78b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_clk {
26*78b3ea9cSJorge Ramirez-Ortiz 	struct io_pa_va base;
27*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t i2c[ARRAY_SIZE(i2c_bus)];
28*78b3ea9cSJorge Ramirez-Ortiz } i2c_clk = {
29*78b3ea9cSJorge Ramirez-Ortiz 	.base.pa = CCM_BASE,
30*78b3ea9cSJorge Ramirez-Ortiz 	.i2c = { I2C_CLK_CGR(1), I2C_CLK_CGR(2), I2C_CLK_CGR(3), },
31*78b3ea9cSJorge Ramirez-Ortiz };
32*78b3ea9cSJorge Ramirez-Ortiz 
33*78b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_mux {
34*78b3ea9cSJorge Ramirez-Ortiz 	struct io_pa_va base;
35*78b3ea9cSJorge Ramirez-Ortiz 	struct imx_i2c_mux_regs {
36*78b3ea9cSJorge Ramirez-Ortiz 		uint32_t scl_mux;
37*78b3ea9cSJorge Ramirez-Ortiz 		uint32_t scl_cfg;
38*78b3ea9cSJorge Ramirez-Ortiz 		uint32_t sda_mux;
39*78b3ea9cSJorge Ramirez-Ortiz 		uint32_t sda_cfg;
40*78b3ea9cSJorge Ramirez-Ortiz 	} i2c[ARRAY_SIZE(i2c_bus)];
41*78b3ea9cSJorge Ramirez-Ortiz } i2c_mux = {
42*78b3ea9cSJorge Ramirez-Ortiz 	.base.pa = IOMUXC_BASE,
43*78b3ea9cSJorge Ramirez-Ortiz 	.i2c = {{ .scl_mux = I2C_MUX_SCL(1), .scl_cfg = I2C_CFG_SCL(1),
44*78b3ea9cSJorge Ramirez-Ortiz 		.sda_mux = I2C_MUX_SDA(1), .sda_cfg = I2C_CFG_SDA(1), },
45*78b3ea9cSJorge Ramirez-Ortiz 	       { .scl_mux = I2C_MUX_SCL(2), .scl_cfg = I2C_CFG_SCL(2),
46*78b3ea9cSJorge Ramirez-Ortiz 		.sda_mux = I2C_MUX_SDA(2), .sda_cfg = I2C_CFG_SDA(2), },
47*78b3ea9cSJorge Ramirez-Ortiz 	       { .scl_mux = I2C_MUX_SCL(3), .scl_cfg = I2C_CFG_SCL(3),
48*78b3ea9cSJorge Ramirez-Ortiz 		.sda_mux = I2C_MUX_SDA(3), .sda_cfg = I2C_CFG_SDA(3), },},
49*78b3ea9cSJorge Ramirez-Ortiz };
50*78b3ea9cSJorge Ramirez-Ortiz 
51*78b3ea9cSJorge Ramirez-Ortiz #define I2DR				0x10
52*78b3ea9cSJorge Ramirez-Ortiz #define I2SR				0x0C
53*78b3ea9cSJorge Ramirez-Ortiz #define I2CR				0x08
54*78b3ea9cSJorge Ramirez-Ortiz #define IFDR				0x04
55*78b3ea9cSJorge Ramirez-Ortiz 
56*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_IEN			BIT(7)
57*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_IIEN			BIT(6)
58*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_MSTA			BIT(5)
59*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_MTX			BIT(4)
60*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_TX_NO_AK			BIT(3)
61*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_RSTA			BIT(2)
62*78b3ea9cSJorge Ramirez-Ortiz 
63*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_ICF			BIT(7)
64*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IBB			BIT(5)
65*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IAL			BIT(4)
66*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IIF			BIT(1)
67*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_RX_NO_AK			BIT(0)
68*78b3ea9cSJorge Ramirez-Ortiz 
69*78b3ea9cSJorge Ramirez-Ortiz static uint8_t i2c_io_read8(uint8_t bid, uint32_t address)
70*78b3ea9cSJorge Ramirez-Ortiz {
71*78b3ea9cSJorge Ramirez-Ortiz 	return io_read8(i2c_bus[bid].va + address);
72*78b3ea9cSJorge Ramirez-Ortiz }
73*78b3ea9cSJorge Ramirez-Ortiz 
74*78b3ea9cSJorge Ramirez-Ortiz static void i2c_io_write8(uint8_t bid, uint32_t address, uint8_t data)
75*78b3ea9cSJorge Ramirez-Ortiz {
76*78b3ea9cSJorge Ramirez-Ortiz 	return io_write8(i2c_bus[bid].va + address, data);
77*78b3ea9cSJorge Ramirez-Ortiz }
78*78b3ea9cSJorge Ramirez-Ortiz 
79*78b3ea9cSJorge Ramirez-Ortiz static bool bus_is_idle(uint32_t sr)
80*78b3ea9cSJorge Ramirez-Ortiz {
81*78b3ea9cSJorge Ramirez-Ortiz 	return (sr & I2SR_IBB) == 0;
82*78b3ea9cSJorge Ramirez-Ortiz }
83*78b3ea9cSJorge Ramirez-Ortiz 
84*78b3ea9cSJorge Ramirez-Ortiz static bool bus_is_busy(uint32_t sr)
85*78b3ea9cSJorge Ramirez-Ortiz {
86*78b3ea9cSJorge Ramirez-Ortiz 	return !bus_is_idle(sr);
87*78b3ea9cSJorge Ramirez-Ortiz }
88*78b3ea9cSJorge Ramirez-Ortiz 
89*78b3ea9cSJorge Ramirez-Ortiz static bool isr_active(uint32_t sr)
90*78b3ea9cSJorge Ramirez-Ortiz {
91*78b3ea9cSJorge Ramirez-Ortiz 	return (sr & I2SR_IIF) == I2SR_IIF;
92*78b3ea9cSJorge Ramirez-Ortiz }
93*78b3ea9cSJorge Ramirez-Ortiz 
94*78b3ea9cSJorge Ramirez-Ortiz static struct ifdr_pair {
95*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t divider;
96*78b3ea9cSJorge Ramirez-Ortiz 	uint8_t prescaler;
97*78b3ea9cSJorge Ramirez-Ortiz } ifdr_table[] = {
98*78b3ea9cSJorge Ramirez-Ortiz 	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
99*78b3ea9cSJorge Ramirez-Ortiz 	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
100*78b3ea9cSJorge Ramirez-Ortiz 	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
101*78b3ea9cSJorge Ramirez-Ortiz 	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
102*78b3ea9cSJorge Ramirez-Ortiz 	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
103*78b3ea9cSJorge Ramirez-Ortiz 	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
104*78b3ea9cSJorge Ramirez-Ortiz 	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
105*78b3ea9cSJorge Ramirez-Ortiz 	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
106*78b3ea9cSJorge Ramirez-Ortiz 	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
107*78b3ea9cSJorge Ramirez-Ortiz 	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
108*78b3ea9cSJorge Ramirez-Ortiz 	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
109*78b3ea9cSJorge Ramirez-Ortiz 	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
110*78b3ea9cSJorge Ramirez-Ortiz 	{ 3072,	0x1E }, { 3840,	0x1F }
111*78b3ea9cSJorge Ramirez-Ortiz };
112*78b3ea9cSJorge Ramirez-Ortiz 
113*78b3ea9cSJorge Ramirez-Ortiz static void i2c_set_prescaler(uint8_t bid, uint32_t bps)
114*78b3ea9cSJorge Ramirez-Ortiz {
115*78b3ea9cSJorge Ramirez-Ortiz 	struct ifdr_pair *p = ifdr_table;
116*78b3ea9cSJorge Ramirez-Ortiz 	struct ifdr_pair *q = p + ARRAY_SIZE(ifdr_table) - 1;
117*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t div = (I2C_CLK_RATE + bps - 1) / bps;
118*78b3ea9cSJorge Ramirez-Ortiz 
119*78b3ea9cSJorge Ramirez-Ortiz 	if (div < p->divider)
120*78b3ea9cSJorge Ramirez-Ortiz 		q = p;
121*78b3ea9cSJorge Ramirez-Ortiz 	else if (div > q->divider)
122*78b3ea9cSJorge Ramirez-Ortiz 		p = q;
123*78b3ea9cSJorge Ramirez-Ortiz 
124*78b3ea9cSJorge Ramirez-Ortiz 	while (p != q) {
125*78b3ea9cSJorge Ramirez-Ortiz 		if (div <= p->divider)
126*78b3ea9cSJorge Ramirez-Ortiz 			break;
127*78b3ea9cSJorge Ramirez-Ortiz 		p++;
128*78b3ea9cSJorge Ramirez-Ortiz 	}
129*78b3ea9cSJorge Ramirez-Ortiz 
130*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, IFDR, p->prescaler);
131*78b3ea9cSJorge Ramirez-Ortiz }
132*78b3ea9cSJorge Ramirez-Ortiz 
133*78b3ea9cSJorge Ramirez-Ortiz static void i2c_set_bus_speed(uint8_t bid, int bps)
134*78b3ea9cSJorge Ramirez-Ortiz {
135*78b3ea9cSJorge Ramirez-Ortiz 	/* Enable the clock */
136*78b3ea9cSJorge Ramirez-Ortiz 	io_write32(i2c_clk.base.va + CCM_CCGRx_SET(i2c_clk.i2c[bid]),
137*78b3ea9cSJorge Ramirez-Ortiz 		   CCM_CCGRx_ALWAYS_ON(0));
138*78b3ea9cSJorge Ramirez-Ortiz 
139*78b3ea9cSJorge Ramirez-Ortiz 	i2c_set_prescaler(bid, bps);
140*78b3ea9cSJorge Ramirez-Ortiz }
141*78b3ea9cSJorge Ramirez-Ortiz 
142*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_sync_bus(uint8_t bid, bool (*match)(uint32_t),
143*78b3ea9cSJorge Ramirez-Ortiz 			       uint32_t *status)
144*78b3ea9cSJorge Ramirez-Ortiz {
145*78b3ea9cSJorge Ramirez-Ortiz 	uint64_t tref = timeout_init_us(100000);
146*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t sr = 0;
147*78b3ea9cSJorge Ramirez-Ortiz 
148*78b3ea9cSJorge Ramirez-Ortiz 	while (!timeout_elapsed(tref)) {
149*78b3ea9cSJorge Ramirez-Ortiz 		sr = i2c_io_read8(bid, I2SR);
150*78b3ea9cSJorge Ramirez-Ortiz 		if (sr & I2SR_IAL) {
151*78b3ea9cSJorge Ramirez-Ortiz 			EMSG("bus arbitration lost");
152*78b3ea9cSJorge Ramirez-Ortiz 			i2c_io_write8(bid, I2SR, sr & ~I2SR_IAL);
153*78b3ea9cSJorge Ramirez-Ortiz 			return TEE_ERROR_COMMUNICATION;
154*78b3ea9cSJorge Ramirez-Ortiz 		}
155*78b3ea9cSJorge Ramirez-Ortiz 		if ((*match)(sr)) {
156*78b3ea9cSJorge Ramirez-Ortiz 			if (status)
157*78b3ea9cSJorge Ramirez-Ortiz 				*status = sr;
158*78b3ea9cSJorge Ramirez-Ortiz 			return TEE_SUCCESS;
159*78b3ea9cSJorge Ramirez-Ortiz 		}
160*78b3ea9cSJorge Ramirez-Ortiz 	}
161*78b3ea9cSJorge Ramirez-Ortiz 
162*78b3ea9cSJorge Ramirez-Ortiz 	return TEE_ERROR_BUSY;
163*78b3ea9cSJorge Ramirez-Ortiz }
164*78b3ea9cSJorge Ramirez-Ortiz 
165*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_idle_bus(uint8_t bid)
166*78b3ea9cSJorge Ramirez-Ortiz {
167*78b3ea9cSJorge Ramirez-Ortiz 	uint8_t tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MSTA;
168*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
169*78b3ea9cSJorge Ramirez-Ortiz 
170*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2CR, tmp);
171*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_sync_bus(bid, &bus_is_idle, NULL);
172*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2SR, 0);
173*78b3ea9cSJorge Ramirez-Ortiz 
174*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
175*78b3ea9cSJorge Ramirez-Ortiz }
176*78b3ea9cSJorge Ramirez-Ortiz 
177*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_byte(uint8_t bid, uint8_t byte)
178*78b3ea9cSJorge Ramirez-Ortiz {
179*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
180*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t status = 0;
181*78b3ea9cSJorge Ramirez-Ortiz 
182*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2DR, byte);
183*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_sync_bus(bid, &isr_active, &status);
184*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2SR, 0);
185*78b3ea9cSJorge Ramirez-Ortiz 
186*78b3ea9cSJorge Ramirez-Ortiz 	if (ret == TEE_SUCCESS && (status & I2SR_RX_NO_AK))
187*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_STATE;
188*78b3ea9cSJorge Ramirez-Ortiz 
189*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
190*78b3ea9cSJorge Ramirez-Ortiz }
191*78b3ea9cSJorge Ramirez-Ortiz 
192*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_byte(uint8_t bid, uint8_t *p)
193*78b3ea9cSJorge Ramirez-Ortiz {
194*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
195*78b3ea9cSJorge Ramirez-Ortiz 
196*78b3ea9cSJorge Ramirez-Ortiz 	*p = i2c_io_read8(bid, I2DR);
197*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_sync_bus(bid, &isr_active, NULL);
198*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2SR, 0);
199*78b3ea9cSJorge Ramirez-Ortiz 
200*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
201*78b3ea9cSJorge Ramirez-Ortiz }
202*78b3ea9cSJorge Ramirez-Ortiz 
203*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_data(uint8_t bid, const uint8_t *buf, int len)
204*78b3ea9cSJorge Ramirez-Ortiz {
205*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
206*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t tmp = 0;
207*78b3ea9cSJorge Ramirez-Ortiz 
208*78b3ea9cSJorge Ramirez-Ortiz 	if (!len)
209*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_SUCCESS;
210*78b3ea9cSJorge Ramirez-Ortiz 
211*78b3ea9cSJorge Ramirez-Ortiz 	tmp = i2c_io_read8(bid, I2CR) | I2CR_MTX | I2CR_TX_NO_AK;
212*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2CR, tmp);
213*78b3ea9cSJorge Ramirez-Ortiz 
214*78b3ea9cSJorge Ramirez-Ortiz 	while (len--) {
215*78b3ea9cSJorge Ramirez-Ortiz 		ret = i2c_write_byte(bid, *buf++);
216*78b3ea9cSJorge Ramirez-Ortiz 		if (ret != TEE_SUCCESS)
217*78b3ea9cSJorge Ramirez-Ortiz 			return ret;
218*78b3ea9cSJorge Ramirez-Ortiz 	}
219*78b3ea9cSJorge Ramirez-Ortiz 
220*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
221*78b3ea9cSJorge Ramirez-Ortiz }
222*78b3ea9cSJorge Ramirez-Ortiz 
223*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_data(uint8_t bid, uint8_t *buf, int len)
224*78b3ea9cSJorge Ramirez-Ortiz {
225*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
226*78b3ea9cSJorge Ramirez-Ortiz 	uint8_t dummy = 0;
227*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t tmp = 0;
228*78b3ea9cSJorge Ramirez-Ortiz 
229*78b3ea9cSJorge Ramirez-Ortiz 	if (!len)
230*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_SUCCESS;
231*78b3ea9cSJorge Ramirez-Ortiz 
232*78b3ea9cSJorge Ramirez-Ortiz 	tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MTX;
233*78b3ea9cSJorge Ramirez-Ortiz 	tmp = (len == 1) ? tmp | I2CR_TX_NO_AK : tmp & ~I2CR_TX_NO_AK;
234*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2CR, tmp);
235*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_read8(bid, I2DR);
236*78b3ea9cSJorge Ramirez-Ortiz 
237*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_read_byte(bid, &dummy);
238*78b3ea9cSJorge Ramirez-Ortiz 	if (ret != TEE_SUCCESS)
239*78b3ea9cSJorge Ramirez-Ortiz 		return ret;
240*78b3ea9cSJorge Ramirez-Ortiz 
241*78b3ea9cSJorge Ramirez-Ortiz 	/*
242*78b3ea9cSJorge Ramirez-Ortiz 	 * A data transfer ends when the master signals a stop; for a master
243*78b3ea9cSJorge Ramirez-Ortiz 	 * receiver to terminate a transfer it must inform the slave transmiter
244*78b3ea9cSJorge Ramirez-Ortiz 	 * by not acknowledging the last data byte. This is done by setting the
245*78b3ea9cSJorge Ramirez-Ortiz 	 * transmit acknowledge bit before reading the next-to-last byte.
246*78b3ea9cSJorge Ramirez-Ortiz 	 */
247*78b3ea9cSJorge Ramirez-Ortiz 	do {
248*78b3ea9cSJorge Ramirez-Ortiz 		if (len == 2) {
249*78b3ea9cSJorge Ramirez-Ortiz 			tmp = i2c_io_read8(bid, I2CR) | I2CR_TX_NO_AK;
250*78b3ea9cSJorge Ramirez-Ortiz 			i2c_io_write8(bid, I2CR, tmp);
251*78b3ea9cSJorge Ramirez-Ortiz 		}
252*78b3ea9cSJorge Ramirez-Ortiz 
253*78b3ea9cSJorge Ramirez-Ortiz 		ret = i2c_read_byte(bid, buf++);
254*78b3ea9cSJorge Ramirez-Ortiz 		if (ret != TEE_SUCCESS)
255*78b3ea9cSJorge Ramirez-Ortiz 			return ret;
256*78b3ea9cSJorge Ramirez-Ortiz 	} while (len--);
257*78b3ea9cSJorge Ramirez-Ortiz 
258*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
259*78b3ea9cSJorge Ramirez-Ortiz }
260*78b3ea9cSJorge Ramirez-Ortiz 
261*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init_transfer(uint8_t bid, uint8_t chip)
262*78b3ea9cSJorge Ramirez-Ortiz {
263*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
264*78b3ea9cSJorge Ramirez-Ortiz 	uint32_t tmp = 0;
265*78b3ea9cSJorge Ramirez-Ortiz 
266*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_idle_bus(bid);
267*78b3ea9cSJorge Ramirez-Ortiz 	if (ret != TEE_SUCCESS)
268*78b3ea9cSJorge Ramirez-Ortiz 		return ret;
269*78b3ea9cSJorge Ramirez-Ortiz 
270*78b3ea9cSJorge Ramirez-Ortiz 	/* Enable the interface */
271*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2CR, I2CR_IEN);
272*78b3ea9cSJorge Ramirez-Ortiz 
273*78b3ea9cSJorge Ramirez-Ortiz 	tmp = i2c_io_read8(bid, I2CR) | I2CR_MSTA;
274*78b3ea9cSJorge Ramirez-Ortiz 	i2c_io_write8(bid, I2CR, tmp);
275*78b3ea9cSJorge Ramirez-Ortiz 
276*78b3ea9cSJorge Ramirez-Ortiz 	/* Wait until the bus is active */
277*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_sync_bus(bid, &bus_is_busy, NULL);
278*78b3ea9cSJorge Ramirez-Ortiz 	if (ret != TEE_SUCCESS)
279*78b3ea9cSJorge Ramirez-Ortiz 		return ret;
280*78b3ea9cSJorge Ramirez-Ortiz 
281*78b3ea9cSJorge Ramirez-Ortiz 	/* Slave address on the bus */
282*78b3ea9cSJorge Ramirez-Ortiz 	return i2c_write_data(bid, &chip, 1);
283*78b3ea9cSJorge Ramirez-Ortiz }
284*78b3ea9cSJorge Ramirez-Ortiz 
285*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_read(uint8_t bid, uint8_t chip, uint8_t *buf, int len)
286*78b3ea9cSJorge Ramirez-Ortiz {
287*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
288*78b3ea9cSJorge Ramirez-Ortiz 
289*78b3ea9cSJorge Ramirez-Ortiz 	if (bid >= ARRAY_SIZE(i2c_bus))
290*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
291*78b3ea9cSJorge Ramirez-Ortiz 
292*78b3ea9cSJorge Ramirez-Ortiz 	if ((len && !buf) || chip > 0x7F)
293*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
294*78b3ea9cSJorge Ramirez-Ortiz 
295*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_init_transfer(bid, chip << 1 | BIT(0));
296*78b3ea9cSJorge Ramirez-Ortiz 	if (ret == TEE_SUCCESS)
297*78b3ea9cSJorge Ramirez-Ortiz 		ret = i2c_read_data(bid, buf, len);
298*78b3ea9cSJorge Ramirez-Ortiz 
299*78b3ea9cSJorge Ramirez-Ortiz 	if (i2c_idle_bus(bid) != TEE_SUCCESS)
300*78b3ea9cSJorge Ramirez-Ortiz 		IMSG("bus not idle");
301*78b3ea9cSJorge Ramirez-Ortiz 
302*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
303*78b3ea9cSJorge Ramirez-Ortiz }
304*78b3ea9cSJorge Ramirez-Ortiz 
305*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_write(uint8_t bid, uint8_t chip, const uint8_t *buf, int len)
306*78b3ea9cSJorge Ramirez-Ortiz {
307*78b3ea9cSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
308*78b3ea9cSJorge Ramirez-Ortiz 
309*78b3ea9cSJorge Ramirez-Ortiz 	if (bid >= ARRAY_SIZE(i2c_bus))
310*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
311*78b3ea9cSJorge Ramirez-Ortiz 
312*78b3ea9cSJorge Ramirez-Ortiz 	if ((len && !buf) || chip > 0x7F)
313*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
314*78b3ea9cSJorge Ramirez-Ortiz 
315*78b3ea9cSJorge Ramirez-Ortiz 	ret = i2c_init_transfer(bid, chip << 1);
316*78b3ea9cSJorge Ramirez-Ortiz 	if (ret == TEE_SUCCESS)
317*78b3ea9cSJorge Ramirez-Ortiz 		ret = i2c_write_data(bid, buf, len);
318*78b3ea9cSJorge Ramirez-Ortiz 
319*78b3ea9cSJorge Ramirez-Ortiz 	if (i2c_idle_bus(bid) != TEE_SUCCESS)
320*78b3ea9cSJorge Ramirez-Ortiz 		IMSG("bus not idle");
321*78b3ea9cSJorge Ramirez-Ortiz 
322*78b3ea9cSJorge Ramirez-Ortiz 	return ret;
323*78b3ea9cSJorge Ramirez-Ortiz }
324*78b3ea9cSJorge Ramirez-Ortiz 
325*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_probe(uint8_t bid, uint8_t chip)
326*78b3ea9cSJorge Ramirez-Ortiz {
327*78b3ea9cSJorge Ramirez-Ortiz 	if (bid >= ARRAY_SIZE(i2c_bus))
328*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
329*78b3ea9cSJorge Ramirez-Ortiz 
330*78b3ea9cSJorge Ramirez-Ortiz 	if (chip > 0x7F)
331*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
332*78b3ea9cSJorge Ramirez-Ortiz 
333*78b3ea9cSJorge Ramirez-Ortiz 	return imx_i2c_write(bid, chip, NULL, 0);
334*78b3ea9cSJorge Ramirez-Ortiz }
335*78b3ea9cSJorge Ramirez-Ortiz 
336*78b3ea9cSJorge Ramirez-Ortiz /*
337*78b3ea9cSJorge Ramirez-Ortiz  * I2C bus initialization: configure the IOMUX and enable the clock.
338*78b3ea9cSJorge Ramirez-Ortiz  * @bid: Bus ID: (0=I2C1), (1=I2C2), (2=I2C3).
339*78b3ea9cSJorge Ramirez-Ortiz  * @bps: Bus baud rate, in bits per second.
340*78b3ea9cSJorge Ramirez-Ortiz  */
341*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_init(uint8_t bid, int bps)
342*78b3ea9cSJorge Ramirez-Ortiz {
343*78b3ea9cSJorge Ramirez-Ortiz 	struct imx_i2c_mux *mux = &i2c_mux;
344*78b3ea9cSJorge Ramirez-Ortiz 
345*78b3ea9cSJorge Ramirez-Ortiz 	if (bid >= ARRAY_SIZE(i2c_bus))
346*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
347*78b3ea9cSJorge Ramirez-Ortiz 
348*78b3ea9cSJorge Ramirez-Ortiz 	if (!bps)
349*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
350*78b3ea9cSJorge Ramirez-Ortiz 
351*78b3ea9cSJorge Ramirez-Ortiz 	io_write32(mux->base.va + mux->i2c[bid].scl_mux, I2C_MUX_VAL(bid));
352*78b3ea9cSJorge Ramirez-Ortiz 	io_write32(mux->base.va + mux->i2c[bid].scl_cfg, I2C_CFG_VAL(bid));
353*78b3ea9cSJorge Ramirez-Ortiz 	io_write32(mux->base.va + mux->i2c[bid].sda_mux, I2C_MUX_VAL(bid));
354*78b3ea9cSJorge Ramirez-Ortiz 	io_write32(mux->base.va + mux->i2c[bid].sda_cfg, I2C_CFG_VAL(bid));
355*78b3ea9cSJorge Ramirez-Ortiz 
356*78b3ea9cSJorge Ramirez-Ortiz 	/* Baud rate in bits per second */
357*78b3ea9cSJorge Ramirez-Ortiz 	i2c_set_bus_speed(bid, bps);
358*78b3ea9cSJorge Ramirez-Ortiz 
359*78b3ea9cSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
360*78b3ea9cSJorge Ramirez-Ortiz }
361*78b3ea9cSJorge Ramirez-Ortiz 
362*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result get_va(paddr_t pa, vaddr_t *va)
363*78b3ea9cSJorge Ramirez-Ortiz {
364*78b3ea9cSJorge Ramirez-Ortiz 	if (!core_mmu_add_mapping(MEM_AREA_IO_SEC, pa, 0x10000))
365*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
366*78b3ea9cSJorge Ramirez-Ortiz 
367*78b3ea9cSJorge Ramirez-Ortiz 	*va = (vaddr_t)phys_to_virt(pa, MEM_AREA_IO_SEC);
368*78b3ea9cSJorge Ramirez-Ortiz 	if (*va)
369*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_SUCCESS;
370*78b3ea9cSJorge Ramirez-Ortiz 
371*78b3ea9cSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
372*78b3ea9cSJorge Ramirez-Ortiz }
373*78b3ea9cSJorge Ramirez-Ortiz 
374*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init(void)
375*78b3ea9cSJorge Ramirez-Ortiz {
376*78b3ea9cSJorge Ramirez-Ortiz 	size_t n = 0;
377*78b3ea9cSJorge Ramirez-Ortiz 
378*78b3ea9cSJorge Ramirez-Ortiz 	if (get_va(i2c_clk.base.pa, &i2c_clk.base.va) != TEE_SUCCESS)
379*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
380*78b3ea9cSJorge Ramirez-Ortiz 
381*78b3ea9cSJorge Ramirez-Ortiz 	if (get_va(i2c_mux.base.pa, &i2c_mux.base.va) != TEE_SUCCESS)
382*78b3ea9cSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
383*78b3ea9cSJorge Ramirez-Ortiz 
384*78b3ea9cSJorge Ramirez-Ortiz 	for (n = 0; n < ARRAY_SIZE(i2c_bus); n++) {
385*78b3ea9cSJorge Ramirez-Ortiz 		if (get_va(i2c_bus[n].pa, &i2c_bus[n].va) != TEE_SUCCESS)
386*78b3ea9cSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
387*78b3ea9cSJorge Ramirez-Ortiz 	}
388*78b3ea9cSJorge Ramirez-Ortiz 
389*78b3ea9cSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
390*78b3ea9cSJorge Ramirez-Ortiz }
391*78b3ea9cSJorge Ramirez-Ortiz 
392*78b3ea9cSJorge Ramirez-Ortiz driver_init(i2c_init);
393