xref: /optee_os/core/drivers/ls_i2c.c (revision bce2f88ab347b28f4149dacef2ad48ac67a500b6)
1819d0141SSahil Malhotra // SPDX-License-Identifier: BSD-2-Clause
2819d0141SSahil Malhotra /*
3819d0141SSahil Malhotra  * Copyright 2021 NXP
4819d0141SSahil Malhotra  *
5819d0141SSahil Malhotra  * I2C driver for I2C Controller
6819d0141SSahil Malhotra  *
7819d0141SSahil Malhotra  */
8819d0141SSahil Malhotra #include <assert.h>
9819d0141SSahil Malhotra #include <drivers/ls_i2c.h>
10819d0141SSahil Malhotra #include <io.h>
11819d0141SSahil Malhotra #include <kernel/boot.h>
12819d0141SSahil Malhotra #include <kernel/dt.h>
13819d0141SSahil Malhotra #include <kernel/delay.h>
14819d0141SSahil Malhotra #include <libfdt.h>
15819d0141SSahil Malhotra #include <mm/core_memprot.h>
16819d0141SSahil Malhotra #include <string.h>
17819d0141SSahil Malhotra 
18819d0141SSahil Malhotra static const char * const i2c_controller_map[] = {
19819d0141SSahil Malhotra 	"/soc/i2c@2000000", "/soc/i2c@2010000", "/soc/i2c@2020000",
20819d0141SSahil Malhotra 	"/soc/i2c@2030000", "/soc/i2c@2040000", "/soc/i2c@2050000",
21819d0141SSahil Malhotra 	"/soc/i2c@2060000", "/soc/i2c@2070000"
22819d0141SSahil Malhotra };
23819d0141SSahil Malhotra 
24819d0141SSahil Malhotra /*
25819d0141SSahil Malhotra  * I2C divisor and ibfd register values when glitch filter is enabled
26819d0141SSahil Malhotra  * In case of duplicate SCL divisor value, the ibfd value with high MUL value
27819d0141SSahil Malhotra  * has been selected. A higher MUL value results in a lower sampling rate of
28819d0141SSahil Malhotra  * the I2C signals. This gives the I2C module greater immunity against glitches
29819d0141SSahil Malhotra  * in the I2C signals.
30819d0141SSahil Malhotra  */
31819d0141SSahil Malhotra static const struct i2c_clock_divisor_pair clk_div_glitch_enabled[] = {
32819d0141SSahil Malhotra 	{ 34, 0x0 },	 { 36, 0x1 },	  { 38, 0x2 },	  { 40, 0x3 },
33819d0141SSahil Malhotra 	{ 42, 0x4 },	 { 44, 0x8 },	  { 48, 0x9 },	  { 52, 0xA },
34819d0141SSahil Malhotra 	{ 54, 0x7 },	 { 56, 0xB },	  { 60, 0xC },	  { 64, 0x10 },
35819d0141SSahil Malhotra 	{ 68, 0x40 },	 { 72, 0x41 },	  { 76, 0x42 },	  { 80, 0x43 },
36819d0141SSahil Malhotra 	{ 84, 0x44 },	 { 88, 0x48 },	  { 96, 0x49 },	  { 104, 0x4A },
37819d0141SSahil Malhotra 	{ 108, 0x47 },	 { 112, 0x4B },	  { 120, 0x4C },  { 128, 0x50 },
38819d0141SSahil Malhotra 	{ 136, 0x80 },	 { 144, 0x81 },	  { 152, 0x82 },  { 160, 0x83 },
39819d0141SSahil Malhotra 	{ 168, 0x84 },	 { 176, 0x88 },	  { 192, 0x89 },  { 208, 0x8A },
40819d0141SSahil Malhotra 	{ 216, 0x87 },	 { 224, 0x8B },	  { 240, 0x8C },  { 256, 0x90 },
41819d0141SSahil Malhotra 	{ 288, 0x91 },	 { 320, 0x92 },	  { 336, 0x8F },  { 352, 0x93 },
42819d0141SSahil Malhotra 	{ 384, 0x98 },	 { 416, 0x95 },	  { 448, 0x99 },  { 480, 0x96 },
43819d0141SSahil Malhotra 	{ 512, 0x9A },	 { 576, 0x9B },	  { 640, 0xA0 },  { 704, 0x9D },
44819d0141SSahil Malhotra 	{ 768, 0xA1 },	 { 832, 0x9E },	  { 896, 0xA2 },  { 960, 0x67 },
45819d0141SSahil Malhotra 	{ 1024, 0xA3 },	 { 1152, 0xA4 },  { 1280, 0xA8 }, { 1536, 0xA9 },
46819d0141SSahil Malhotra 	{ 1792, 0xAA },	 { 1920, 0xA7 },  { 2048, 0xAB }, { 2304, 0xAC },
47819d0141SSahil Malhotra 	{ 2560, 0xB0 },	 { 3072, 0xB1 },  { 3584, 0xB2 }, { 3840, 0xAF },
48819d0141SSahil Malhotra 	{ 4096, 0xB3 },	 { 4608, 0xB4 },  { 5120, 0xB8 }, { 6144, 0xB9 },
49819d0141SSahil Malhotra 	{ 7168, 0xBA },	 { 7680, 0xB7 },  { 8192, 0xBB }, { 9216, 0xBC },
50819d0141SSahil Malhotra 	{ 10240, 0xBD }, { 12288, 0xBE }, { 15360, 0xBF }
51819d0141SSahil Malhotra };
52819d0141SSahil Malhotra 
53819d0141SSahil Malhotra /*
54819d0141SSahil Malhotra  * I2C divisor and ibfd register values when glitch filter is disabled.
55819d0141SSahil Malhotra  * In case of duplicate SCL divisor value, the ibfd value with high MUL value
56819d0141SSahil Malhotra  * has been selected. A higher MUL value results in a lower sampling rate of
57819d0141SSahil Malhotra  * the I2C signals. This gives the I2C module greater immunity against glitches
58819d0141SSahil Malhotra  * in the I2C signals.
59819d0141SSahil Malhotra  */
60819d0141SSahil Malhotra static const struct i2c_clock_divisor_pair clk_div_glitch_disabled[] = {
61819d0141SSahil Malhotra 	{ 20, 0x0 },	 { 22, 0x1 },	  { 24, 0x2 },	  { 26, 0x3 },
62819d0141SSahil Malhotra 	{ 28, 0x8 },	 { 30, 0x5 },	  { 32, 0x9 },	  { 34, 0x6 },
63819d0141SSahil Malhotra 	{ 36, 0x0A },	 { 40, 0x40 },	  { 44, 0x41 },	  { 48, 0x42 },
64819d0141SSahil Malhotra 	{ 52, 0x43 },	 { 56, 0x48 },	  { 60, 0x45 },	  { 64, 0x49 },
65819d0141SSahil Malhotra 	{ 68, 0x46 },	 { 72, 0x4A },	  { 80, 0x80 },	  { 88, 0x81 },
66819d0141SSahil Malhotra 	{ 96, 0x82 },	 { 104, 0x83 },	  { 112, 0x88 },  { 120, 0x85 },
67819d0141SSahil Malhotra 	{ 128, 0x89 },	 { 136, 0x86 },	  { 144, 0x8A },  { 160, 0x8B },
68819d0141SSahil Malhotra 	{ 176, 0x8C },	 { 192, 0x90 },	  { 208, 0x56 },  { 224, 0x91 },
69819d0141SSahil Malhotra 	{ 240, 0x1F },	 { 256, 0x92 },	  { 272, 0x8F },  { 288, 0x93 },
70819d0141SSahil Malhotra 	{ 320, 0x98 },	 { 352, 0x95 },	  { 384, 0x99 },  { 416, 0x96 },
71819d0141SSahil Malhotra 	{ 448, 0x9A },	 { 480, 0x5F },	  { 512, 0x9B },  { 576, 0x9C },
72819d0141SSahil Malhotra 	{ 640, 0xA0 },	 { 768, 0xA1 },	  { 896, 0xA2 },  { 960, 0x9F },
73819d0141SSahil Malhotra 	{ 1024, 0xA3 },	 { 1152, 0xA4 },  { 1280, 0xA8 }, { 1536, 0xA9 },
74819d0141SSahil Malhotra 	{ 1792, 0xAA },	 { 1920, 0xA7 },  { 2048, 0xAB }, { 2304, 0xAC },
75819d0141SSahil Malhotra 	{ 2560, 0xAD },	 { 3072, 0xB1 },  { 3584, 0xB2 }, { 3840, 0xAF },
76819d0141SSahil Malhotra 	{ 4096, 0xB3 },	 { 4608, 0xB4 },  { 5120, 0xB8 }, { 6144, 0xB9 },
77819d0141SSahil Malhotra 	{ 7168, 0xBA },	 { 7680, 0xB7 },  { 8192, 0xBB }, { 9216, 0xBC },
78819d0141SSahil Malhotra 	{ 10240, 0xBD }, { 12288, 0xBE }, { 15360, 0xBF }
79819d0141SSahil Malhotra };
80819d0141SSahil Malhotra 
i2c_reset(vaddr_t base)81819d0141SSahil Malhotra void i2c_reset(vaddr_t base)
82819d0141SSahil Malhotra {
83819d0141SSahil Malhotra 	struct i2c_regs *regs = (struct i2c_regs *)base;
84819d0141SSahil Malhotra 
85819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_MDIS);
86819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibsr, I2C_IBSR_IBAL | I2C_IBSR_IBIF);
87819d0141SSahil Malhotra 	io_clrbits8((vaddr_t)&regs->ibcr, I2C_IBCR_IBIE | I2C_IBCR_DMAEN);
88819d0141SSahil Malhotra 	io_clrbits8((vaddr_t)&regs->ibic, I2C_IBIC_BIIE);
89819d0141SSahil Malhotra }
90819d0141SSahil Malhotra 
91819d0141SSahil Malhotra /*
92819d0141SSahil Malhotra  * Get I2c Bus Frequency Divider Register value based on clock_divisor
93819d0141SSahil Malhotra  * and if the glitch is enabled or not in I2c controller.
94819d0141SSahil Malhotra  * base			Base address of I2C controller
95819d0141SSahil Malhotra  * clock_divisor	Clock Divisor
96819d0141SSahil Malhotra  */
i2c_get_ibfd(vaddr_t base,uint16_t clock_divisor)97819d0141SSahil Malhotra static uint8_t i2c_get_ibfd(vaddr_t base, uint16_t clock_divisor)
98819d0141SSahil Malhotra {
99819d0141SSahil Malhotra 	struct i2c_regs *regs = (struct i2c_regs *)base;
100819d0141SSahil Malhotra 	const struct i2c_clock_divisor_pair *dpair = NULL;
101819d0141SSahil Malhotra 	size_t dpair_sz = 0;
102819d0141SSahil Malhotra 	unsigned int n = 0;
103819d0141SSahil Malhotra 
104819d0141SSahil Malhotra 	if (io_read8((vaddr_t)&regs->ibdbg) & I2C_IBDBG_GLFLT_EN) {
105819d0141SSahil Malhotra 		dpair = clk_div_glitch_enabled;
106819d0141SSahil Malhotra 		dpair_sz = ARRAY_SIZE(clk_div_glitch_enabled);
107819d0141SSahil Malhotra 	} else {
108819d0141SSahil Malhotra 		dpair = clk_div_glitch_disabled;
109819d0141SSahil Malhotra 		dpair_sz = ARRAY_SIZE(clk_div_glitch_disabled);
110819d0141SSahil Malhotra 	}
111819d0141SSahil Malhotra 
112819d0141SSahil Malhotra 	for (n = 0; n < dpair_sz - 1; n++)
113819d0141SSahil Malhotra 		if (clock_divisor < dpair[n].divisor)
114819d0141SSahil Malhotra 			break;
115819d0141SSahil Malhotra 
116819d0141SSahil Malhotra 	return dpair[n].ibfd;
117819d0141SSahil Malhotra }
118819d0141SSahil Malhotra 
i2c_init(struct ls_i2c_data * i2c_data)119819d0141SSahil Malhotra TEE_Result i2c_init(struct ls_i2c_data *i2c_data)
120819d0141SSahil Malhotra {
121819d0141SSahil Malhotra 	struct i2c_regs *regs = NULL;
122819d0141SSahil Malhotra 	uint16_t clock_divisor = 0;
123819d0141SSahil Malhotra 	uint8_t ibfd = 0; /* I2c Bus Frequency Divider Register */
124819d0141SSahil Malhotra 	size_t size = 0;
125819d0141SSahil Malhotra 	int node = 0;
126819d0141SSahil Malhotra 	vaddr_t ctrl_base = 0;
127819d0141SSahil Malhotra 	void *fdt = NULL;
128819d0141SSahil Malhotra 
129819d0141SSahil Malhotra 	/*
130819d0141SSahil Malhotra 	 * First get the I2C Controller base address from the DTB
131819d0141SSahil Malhotra 	 * if DTB present and if the I2C Controller defined in it.
132819d0141SSahil Malhotra 	 */
133819d0141SSahil Malhotra 	fdt = get_embedded_dt();
134819d0141SSahil Malhotra 	if (!fdt) {
135*bce2f88aSVincent Mailhol 		EMSG("Unable to get the Embedded DTB, I2C init failed");
136819d0141SSahil Malhotra 		return TEE_ERROR_GENERIC;
137819d0141SSahil Malhotra 	}
138819d0141SSahil Malhotra 
139819d0141SSahil Malhotra 	node = fdt_path_offset(fdt,
140819d0141SSahil Malhotra 			       i2c_controller_map[i2c_data->i2c_controller]);
141819d0141SSahil Malhotra 	if (node > 0) {
142a5d5bbc8SVesa Jääskeläinen 		if (dt_map_dev(fdt, node, &ctrl_base, &size,
143a5d5bbc8SVesa Jääskeläinen 			       DT_MAP_AUTO) < 0) {
144819d0141SSahil Malhotra 			EMSG("Unable to get virtual address");
145819d0141SSahil Malhotra 			return TEE_ERROR_GENERIC;
146819d0141SSahil Malhotra 		}
147819d0141SSahil Malhotra 	} else {
148819d0141SSahil Malhotra 		EMSG("Unable to get I2C offset node");
149819d0141SSahil Malhotra 		return TEE_ERROR_ITEM_NOT_FOUND;
150819d0141SSahil Malhotra 	}
151819d0141SSahil Malhotra 
152819d0141SSahil Malhotra 	i2c_data->base = ctrl_base;
153819d0141SSahil Malhotra 
154819d0141SSahil Malhotra 	regs = (struct i2c_regs *)ctrl_base;
155819d0141SSahil Malhotra 
156819d0141SSahil Malhotra 	clock_divisor = (i2c_data->i2c_bus_clock + i2c_data->speed - 1) /
157819d0141SSahil Malhotra 			i2c_data->speed;
158819d0141SSahil Malhotra 	ibfd = i2c_get_ibfd(ctrl_base, clock_divisor);
159819d0141SSahil Malhotra 
160819d0141SSahil Malhotra 	io_write8((vaddr_t)&regs->ibfd, ibfd);
161819d0141SSahil Malhotra 
162819d0141SSahil Malhotra 	i2c_reset(ctrl_base);
163819d0141SSahil Malhotra 
164819d0141SSahil Malhotra 	return TEE_SUCCESS;
165819d0141SSahil Malhotra }
166819d0141SSahil Malhotra 
167819d0141SSahil Malhotra /*
168819d0141SSahil Malhotra  * Check if I2C bus is busy with previous transaction or not.
169819d0141SSahil Malhotra  * regs         pointer to I2c controller registers
170819d0141SSahil Malhotra  * test_busy	this flag tells if we need to check the busy bit in IBSR reg
171819d0141SSahil Malhotra  */
i2c_bus_test_bus_busy(struct i2c_regs * regs,bool test_busy)172819d0141SSahil Malhotra static TEE_Result i2c_bus_test_bus_busy(struct i2c_regs *regs, bool test_busy)
173819d0141SSahil Malhotra {
174819d0141SSahil Malhotra 	unsigned int n = 0;
175819d0141SSahil Malhotra 	uint8_t reg = 0;
176819d0141SSahil Malhotra 
177819d0141SSahil Malhotra 	for (n = 0; n < I2C_NUM_RETRIES; n++) {
178819d0141SSahil Malhotra 		reg = io_read8((vaddr_t)&regs->ibsr);
179819d0141SSahil Malhotra 
180819d0141SSahil Malhotra 		if (reg & I2C_IBSR_IBAL) {
181819d0141SSahil Malhotra 			io_write8((vaddr_t)&regs->ibsr, reg);
182819d0141SSahil Malhotra 			return TEE_ERROR_BUSY;
183819d0141SSahil Malhotra 		}
184819d0141SSahil Malhotra 
185819d0141SSahil Malhotra 		if (test_busy && (reg & I2C_IBSR_IBB))
186819d0141SSahil Malhotra 			break;
187819d0141SSahil Malhotra 
188819d0141SSahil Malhotra 		if (!test_busy && !(reg & I2C_IBSR_IBB))
189819d0141SSahil Malhotra 			break;
190819d0141SSahil Malhotra 
191819d0141SSahil Malhotra 		mdelay(1);
192819d0141SSahil Malhotra 	}
193819d0141SSahil Malhotra 
194819d0141SSahil Malhotra 	if (n == I2C_NUM_RETRIES)
195819d0141SSahil Malhotra 		return TEE_ERROR_BUSY;
196819d0141SSahil Malhotra 
197819d0141SSahil Malhotra 	return TEE_SUCCESS;
198819d0141SSahil Malhotra }
199819d0141SSahil Malhotra 
200819d0141SSahil Malhotra /*
201819d0141SSahil Malhotra  * Check if data transfer to/from i2c controller is complete.
202819d0141SSahil Malhotra  * regs		pointer to I2c controller registers
203819d0141SSahil Malhotra  * test_rx_ack	this flag tells if we need to check RXAK bit in IBSR reg
204819d0141SSahil Malhotra  */
i2c_transfer_complete(struct i2c_regs * regs,bool test_rx_ack)205819d0141SSahil Malhotra static TEE_Result i2c_transfer_complete(struct i2c_regs *regs, bool test_rx_ack)
206819d0141SSahil Malhotra {
207819d0141SSahil Malhotra 	unsigned int n = 0;
208819d0141SSahil Malhotra 	uint8_t reg = 0;
209819d0141SSahil Malhotra 
210819d0141SSahil Malhotra 	for (n = 0; n < I2C_NUM_RETRIES; n++) {
211819d0141SSahil Malhotra 		reg = io_read8((vaddr_t)&regs->ibsr);
212819d0141SSahil Malhotra 
213819d0141SSahil Malhotra 		if (reg & I2C_IBSR_IBIF) {
214819d0141SSahil Malhotra 			/* Write 1 to clear the IBIF field */
215819d0141SSahil Malhotra 			io_write8((vaddr_t)&regs->ibsr, reg);
216819d0141SSahil Malhotra 			break;
217819d0141SSahil Malhotra 		}
218819d0141SSahil Malhotra 		mdelay(1);
219819d0141SSahil Malhotra 	}
220819d0141SSahil Malhotra 
221819d0141SSahil Malhotra 	if (n == I2C_NUM_RETRIES)
222819d0141SSahil Malhotra 		return TEE_ERROR_BUSY;
223819d0141SSahil Malhotra 
224819d0141SSahil Malhotra 	if (test_rx_ack && (reg & I2C_IBSR_RXAK))
225819d0141SSahil Malhotra 		return TEE_ERROR_NO_DATA;
226819d0141SSahil Malhotra 
227819d0141SSahil Malhotra 	if (reg & I2C_IBSR_TCF)
228819d0141SSahil Malhotra 		return TEE_SUCCESS;
229819d0141SSahil Malhotra 
230819d0141SSahil Malhotra 	return TEE_ERROR_GENERIC;
231819d0141SSahil Malhotra }
232819d0141SSahil Malhotra 
233819d0141SSahil Malhotra /*
234819d0141SSahil Malhotra  * Read data from I2c controller.
235819d0141SSahil Malhotra  * regs			pointer to I2c controller registers
236819d0141SSahil Malhotra  * slave_address	slave address from which to read
237819d0141SSahil Malhotra  * operation		pointer to i2c_operation struct
238819d0141SSahil Malhotra  * is_last_operation	if current operation is last operation
239819d0141SSahil Malhotra  */
i2c_read(struct i2c_regs * regs,unsigned int slave_address,struct i2c_operation * operation,bool is_last_operation)240819d0141SSahil Malhotra static TEE_Result i2c_read(struct i2c_regs *regs, unsigned int slave_address,
241819d0141SSahil Malhotra 			   struct i2c_operation *operation,
242819d0141SSahil Malhotra 			   bool is_last_operation)
243819d0141SSahil Malhotra {
244819d0141SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
245819d0141SSahil Malhotra 	unsigned int n = 0;
246819d0141SSahil Malhotra 
247819d0141SSahil Malhotra 	/* Write Slave Address */
248819d0141SSahil Malhotra 	io_write8((vaddr_t)&regs->ibdr, (slave_address << 0x1) | BIT(0));
249819d0141SSahil Malhotra 	res = i2c_transfer_complete(regs, I2C_BUS_TEST_RX_ACK);
250819d0141SSahil Malhotra 	if (res)
251819d0141SSahil Malhotra 		return res;
252819d0141SSahil Malhotra 
253819d0141SSahil Malhotra 	/* select Receive mode. */
254819d0141SSahil Malhotra 	io_clrbits8((vaddr_t)&regs->ibcr, I2C_IBCR_TXRX);
255819d0141SSahil Malhotra 	if (operation->length_in_bytes > 1) {
256819d0141SSahil Malhotra 		/* Set No ACK = 0 */
257819d0141SSahil Malhotra 		io_clrbits8((vaddr_t)&regs->ibcr, I2C_IBCR_NOACK);
258819d0141SSahil Malhotra 	}
259819d0141SSahil Malhotra 
260819d0141SSahil Malhotra 	/* Perform a dummy read to initiate the receive operation. */
261819d0141SSahil Malhotra 	io_read8((vaddr_t)&regs->ibdr);
262819d0141SSahil Malhotra 
263819d0141SSahil Malhotra 	for (n = 0; n < operation->length_in_bytes; n++) {
264819d0141SSahil Malhotra 		res = i2c_transfer_complete(regs, I2C_BUS_NO_TEST_RX_ACK);
265819d0141SSahil Malhotra 		if (res)
266819d0141SSahil Malhotra 			return res;
267819d0141SSahil Malhotra 		if (n == (operation->length_in_bytes - 2)) {
268819d0141SSahil Malhotra 			/* Set No ACK = 1 */
269819d0141SSahil Malhotra 			io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_NOACK);
270819d0141SSahil Malhotra 		} else if (n == (operation->length_in_bytes - 1)) {
271819d0141SSahil Malhotra 			if (!is_last_operation) {
272819d0141SSahil Malhotra 				/* select Transmit mode (for repeat start) */
273819d0141SSahil Malhotra 				io_setbits8((vaddr_t)&regs->ibcr,
274819d0141SSahil Malhotra 					    I2C_IBCR_TXRX);
275819d0141SSahil Malhotra 			} else {
276819d0141SSahil Malhotra 				/* Generate Stop Signal */
277819d0141SSahil Malhotra 				io_clrbits8((vaddr_t)&regs->ibcr,
278819d0141SSahil Malhotra 					    (I2C_IBCR_MSSL | I2C_IBCR_TXRX));
279819d0141SSahil Malhotra 				res = i2c_bus_test_bus_busy(regs,
280819d0141SSahil Malhotra 							    I2C_BUS_TEST_IDLE);
281819d0141SSahil Malhotra 				if (res)
282819d0141SSahil Malhotra 					return res;
283819d0141SSahil Malhotra 			}
284819d0141SSahil Malhotra 		}
285819d0141SSahil Malhotra 		operation->buffer[n] = io_read8((vaddr_t)&regs->ibdr);
286819d0141SSahil Malhotra 	}
287819d0141SSahil Malhotra 
288819d0141SSahil Malhotra 	return TEE_SUCCESS;
289819d0141SSahil Malhotra }
290819d0141SSahil Malhotra 
291819d0141SSahil Malhotra /*
292819d0141SSahil Malhotra  * Write data to I2c controller
293819d0141SSahil Malhotra  * regs			pointer to I2c controller registers
294819d0141SSahil Malhotra  * slave_address	slave address from which to read
295819d0141SSahil Malhotra  * operation		pointer to i2c_operation struct
296819d0141SSahil Malhotra  */
i2c_write(struct i2c_regs * regs,unsigned int slave_address,struct i2c_operation * operation)297819d0141SSahil Malhotra static TEE_Result i2c_write(struct i2c_regs *regs, unsigned int slave_address,
298819d0141SSahil Malhotra 			    struct i2c_operation *operation)
299819d0141SSahil Malhotra {
300819d0141SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
301819d0141SSahil Malhotra 	unsigned int n = 0;
302819d0141SSahil Malhotra 
303819d0141SSahil Malhotra 	/* Write Slave Address */
304819d0141SSahil Malhotra 	io_write8((vaddr_t)&regs->ibdr,
305819d0141SSahil Malhotra 		  (slave_address << 0x1) & ~(BIT(0)));
306819d0141SSahil Malhotra 	res = i2c_transfer_complete(regs, I2C_BUS_TEST_RX_ACK);
307819d0141SSahil Malhotra 	if (res)
308819d0141SSahil Malhotra 		return res;
309819d0141SSahil Malhotra 
310819d0141SSahil Malhotra 	/* Write Data */
311819d0141SSahil Malhotra 	for (n = 0; n < operation->length_in_bytes; n++) {
312819d0141SSahil Malhotra 		io_write8((vaddr_t)&regs->ibdr, operation->buffer[n]);
313819d0141SSahil Malhotra 		res = i2c_transfer_complete(regs, I2C_BUS_TEST_RX_ACK);
314819d0141SSahil Malhotra 		if (res)
315819d0141SSahil Malhotra 			return res;
316819d0141SSahil Malhotra 	}
317819d0141SSahil Malhotra 
318819d0141SSahil Malhotra 	return TEE_SUCCESS;
319819d0141SSahil Malhotra }
320819d0141SSahil Malhotra 
321819d0141SSahil Malhotra /*
322819d0141SSahil Malhotra  * Generate Stop Signal and disable I2C controller.
323819d0141SSahil Malhotra  * regs		pointer to I2c controller registers
324819d0141SSahil Malhotra  */
i2c_stop(struct i2c_regs * regs)325819d0141SSahil Malhotra static TEE_Result i2c_stop(struct i2c_regs *regs)
326819d0141SSahil Malhotra {
327819d0141SSahil Malhotra 	TEE_Result res = TEE_SUCCESS;
328819d0141SSahil Malhotra 	uint8_t reg = 0;
329819d0141SSahil Malhotra 
330819d0141SSahil Malhotra 	reg = io_read8((vaddr_t)&regs->ibsr);
331819d0141SSahil Malhotra 	if (reg & I2C_IBSR_IBB) {
332819d0141SSahil Malhotra 		/* Generate Stop Signal */
333819d0141SSahil Malhotra 		io_clrbits8((vaddr_t)&regs->ibcr,
334819d0141SSahil Malhotra 			    I2C_IBCR_MSSL | I2C_IBCR_TXRX);
335819d0141SSahil Malhotra 		res = i2c_bus_test_bus_busy(regs, I2C_BUS_TEST_IDLE);
336819d0141SSahil Malhotra 		if (res)
337819d0141SSahil Malhotra 			return res;
338819d0141SSahil Malhotra 	}
339819d0141SSahil Malhotra 
340819d0141SSahil Malhotra 	/* Disable I2c Controller */
341819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_MDIS);
342819d0141SSahil Malhotra 
343819d0141SSahil Malhotra 	return TEE_SUCCESS;
344819d0141SSahil Malhotra }
345819d0141SSahil Malhotra 
346819d0141SSahil Malhotra /*
347819d0141SSahil Malhotra  * Generate Start Signal and set I2C controller in transmit mode.
348819d0141SSahil Malhotra  * regs		pointer to I2c controller registers
349819d0141SSahil Malhotra  */
i2c_start(struct i2c_regs * regs)350819d0141SSahil Malhotra static TEE_Result i2c_start(struct i2c_regs *regs)
351819d0141SSahil Malhotra {
352819d0141SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
353819d0141SSahil Malhotra 
354819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibsr, I2C_IBSR_IBAL | I2C_IBSR_IBIF);
355819d0141SSahil Malhotra 	io_clrbits8((vaddr_t)&regs->ibcr, I2C_IBCR_MDIS);
356819d0141SSahil Malhotra 
357819d0141SSahil Malhotra 	/* Wait controller to be stable */
358819d0141SSahil Malhotra 	mdelay(1);
359819d0141SSahil Malhotra 
360819d0141SSahil Malhotra 	/* Generate Start Signal */
361819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_MSSL);
362819d0141SSahil Malhotra 	res = i2c_bus_test_bus_busy(regs, I2C_BUS_TEST_BUSY);
363819d0141SSahil Malhotra 	if (res)
364819d0141SSahil Malhotra 		return res;
365819d0141SSahil Malhotra 
366819d0141SSahil Malhotra 	/* Select Transmit Mode. set No ACK = 1 */
367819d0141SSahil Malhotra 	io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_TXRX | I2C_IBCR_NOACK);
368819d0141SSahil Malhotra 
369819d0141SSahil Malhotra 	return TEE_SUCCESS;
370819d0141SSahil Malhotra }
371819d0141SSahil Malhotra 
i2c_bus_xfer(vaddr_t base,unsigned int slave_address,struct i2c_operation * i2c_operation,unsigned int operation_count)372819d0141SSahil Malhotra TEE_Result i2c_bus_xfer(vaddr_t base, unsigned int slave_address,
373819d0141SSahil Malhotra 			struct i2c_operation *i2c_operation,
374819d0141SSahil Malhotra 			unsigned int operation_count)
375819d0141SSahil Malhotra {
376819d0141SSahil Malhotra 	unsigned int n = 0;
377819d0141SSahil Malhotra 	struct i2c_regs *regs = (struct i2c_regs *)base;
378819d0141SSahil Malhotra 	struct i2c_operation *operation = NULL;
379819d0141SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
380819d0141SSahil Malhotra 	bool is_last_operation = false;
381819d0141SSahil Malhotra 
382819d0141SSahil Malhotra 	res = i2c_bus_test_bus_busy(regs, I2C_BUS_TEST_IDLE);
383819d0141SSahil Malhotra 	if (res)
384819d0141SSahil Malhotra 		goto out;
385819d0141SSahil Malhotra 
386819d0141SSahil Malhotra 	res = i2c_start(regs);
387819d0141SSahil Malhotra 	if (res)
388819d0141SSahil Malhotra 		goto out;
389819d0141SSahil Malhotra 
390819d0141SSahil Malhotra 	for (n = 0, operation = i2c_operation;
391819d0141SSahil Malhotra 	     n < operation_count; n++, operation++) {
392819d0141SSahil Malhotra 		if (n == (operation_count - 1))
393819d0141SSahil Malhotra 			is_last_operation = true;
394819d0141SSahil Malhotra 
395819d0141SSahil Malhotra 		/* Send repeat start after first transmit/receive */
396819d0141SSahil Malhotra 		if (n) {
397819d0141SSahil Malhotra 			io_setbits8((vaddr_t)&regs->ibcr, I2C_IBCR_RSTA);
398819d0141SSahil Malhotra 			res = i2c_bus_test_bus_busy(regs, I2C_BUS_TEST_BUSY);
399819d0141SSahil Malhotra 			if (res)
400819d0141SSahil Malhotra 				goto out;
401819d0141SSahil Malhotra 		}
402819d0141SSahil Malhotra 
403819d0141SSahil Malhotra 		/* Read/write data */
404819d0141SSahil Malhotra 		if (operation->flags & I2C_FLAG_READ)
405819d0141SSahil Malhotra 			res = i2c_read(regs, slave_address, operation,
406819d0141SSahil Malhotra 				       is_last_operation);
407819d0141SSahil Malhotra 		else
408819d0141SSahil Malhotra 			res = i2c_write(regs, slave_address, operation);
409819d0141SSahil Malhotra 		if (res)
410819d0141SSahil Malhotra 			goto out;
411819d0141SSahil Malhotra 	}
412819d0141SSahil Malhotra 
413819d0141SSahil Malhotra out:
414819d0141SSahil Malhotra 	i2c_stop(regs);
415819d0141SSahil Malhotra 
416819d0141SSahil Malhotra 	return res;
417819d0141SSahil Malhotra }
418