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)®s->ibcr, I2C_IBCR_MDIS);
86819d0141SSahil Malhotra io_setbits8((vaddr_t)®s->ibsr, I2C_IBSR_IBAL | I2C_IBSR_IBIF);
87819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->ibcr, I2C_IBCR_IBIE | I2C_IBCR_DMAEN);
88819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->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)®s->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)®s->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)®s->ibsr);
179819d0141SSahil Malhotra
180819d0141SSahil Malhotra if (reg & I2C_IBSR_IBAL) {
181819d0141SSahil Malhotra io_write8((vaddr_t)®s->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)®s->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)®s->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)®s->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)®s->ibcr, I2C_IBCR_TXRX);
255819d0141SSahil Malhotra if (operation->length_in_bytes > 1) {
256819d0141SSahil Malhotra /* Set No ACK = 0 */
257819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->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)®s->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)®s->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)®s->ibcr,
274819d0141SSahil Malhotra I2C_IBCR_TXRX);
275819d0141SSahil Malhotra } else {
276819d0141SSahil Malhotra /* Generate Stop Signal */
277819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->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)®s->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)®s->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)®s->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)®s->ibsr);
331819d0141SSahil Malhotra if (reg & I2C_IBSR_IBB) {
332819d0141SSahil Malhotra /* Generate Stop Signal */
333819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->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)®s->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)®s->ibsr, I2C_IBSR_IBAL | I2C_IBSR_IBIF);
355819d0141SSahil Malhotra io_clrbits8((vaddr_t)®s->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)®s->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)®s->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)®s->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