1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017-09-06 ���� first version
9 */
10
11 // ��װӲ��i2c�ӿ�
12
13
14 #include "ls1c_public.h"
15 #include "ls1c_regs.h"
16 #include "ls1c_clock.h"
17 #include "ls1c_i2c.h"
18 #include "ls1c_delay.h"
19
20
21
22 /*
23 * I2C�����Ĵ�����Ի���ַ��ƫ��
24 * �������ݼĴ����ͽ������ݼĴ�����ƫ������ͬ��
25 * ����Ĵ�����״̬�Ĵ�����ƫ������ͬ�ģ���ͬ��������Ĵ���ֻд��״̬�Ĵ���ֻ��
26 */
27 #define LS1C_I2C_PRER_LOW_OFFSET (0) // ��Ƶ���������ֽڼĴ���ƫ��
28 #define LS1C_I2C_PRER_HIGH_OFFSET (1) // ��Ƶ���������ֽڼĴ���ƫ��
29 #define LS1C_I2C_CONTROL_OFFSET (2) // ���ƼĴ���ƫ��
30 #define LS1C_I2C_DATA_OFFSET (3) // �������ݼĴ����ͽ������ݼĴ�����ƫ������ͬ��
31 #define LS1C_I2C_CMD_OFFSET (4) // ����Ĵ���ƫ�ƣ�ֻд
32 #define LS1C_I2C_STATUS_OFFSET (4) // ״̬�Ĵ���ƫ�ƣ�ֻ��
33
34
35 // ���ƼĴ�����λ��
36 #define LS1C_I2C_CONTROL_EN (0x80) // i2cģ��ʹ��
37 #define LS1C_I2C_CONTROL_IEN (0x40) // �ж�ʹ��
38
39 // ����Ĵ�����λ��
40 #define LS1C_I2C_CMD_START (0x90) // ����START�ź�
41 #define LS1C_I2C_CMD_STOP (0x40) // ����STOP�ź�
42 #define LS1C_I2C_CMD_READ (0x20) // �������źţ�������ACK�ź�
43 #define LS1C_I2C_CMD_WRITE (0x10) // ����д�ź�
44 #define LS1C_I2C_CMD_READ_ACK (0x20) // ����ACK�źţ�����ź���ͬ
45 #define LS1C_I2C_CMD_READ_NACK (0x28) // ����NACK�ź�
46 #define LS1C_I2C_CMD_IACK (0x00) // �����ж�Ӧ���ź�
47
48 // ״̬�Ĵ�����λ��
49 #define LS1C_I2C_STATUS_IF (0x01) // �жϱ�־λ
50 #define LS1C_I2C_STATUS_TIP (0x02) // ָʾ����Ĺ��̡�1�����ڴ��䣻0���������
51 #define LS1C_I2C_STATUS_ARBLOST (0x20) // I2C��ʧȥI2C���ߵĿ���Ȩ
52 #define LS1C_I2C_STATUS_BUSY (0x40) // I2C����æ��־
53 #define LS1C_I2C_STATUS_NACK (0x80) // Ӧ��λ��־��1��û�յ�Ӧ��λ��0���յ�Ӧ��λ
54
55
56 /*
57 * ��ȡָ��i2cģ��Ļ���ַ
58 * @I2Cx I2Cģ��ı��
59 */
i2c_get_base(ls1c_i2c_t I2Cx)60 void *i2c_get_base(ls1c_i2c_t I2Cx)
61 {
62 void *base = NULL;
63
64 switch (I2Cx)
65 {
66 case LS1C_I2C_0:
67 base = (void *)LS1C_I2C0_BASE;
68 break;
69
70 case LS1C_I2C_1:
71 base = (void *)LS1C_I2C1_BASE;
72 break;
73
74 case LS1C_I2C_2:
75 base = (void *)LS1C_I2C2_BASE;
76 break;
77
78 default:
79 base = NULL;
80 break;
81 }
82
83 return base;
84 }
85
86
87 /*
88 * ������Ĵ���д����
89 * @i2c_info_p i2cģ����Ϣ
90 * @cmd ����
91 */
i2c_cmd(ls1c_i2c_info_t * i2c_info_p,unsigned char cmd)92 void i2c_cmd(ls1c_i2c_info_t *i2c_info_p, unsigned char cmd)
93 {
94 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
95
96 reg_write_8(cmd, i2c_base + LS1C_I2C_CMD_OFFSET);
97
98 return ;
99 }
100
101
102 /*
103 * ִ��START�������START�ź�
104 * @i2c_info_p i2cģ����Ϣ
105 */
i2c_cmd_start(ls1c_i2c_info_t * i2c_info_p)106 void i2c_cmd_start(ls1c_i2c_info_t *i2c_info_p)
107 {
108 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_START);
109 return ;
110 }
111
112
113 /*
114 * ִ��STOP�������STOP�ź�
115 * @i2c_info_p i2cģ����Ϣ
116 */
i2c_cmd_stop(ls1c_i2c_info_t * i2c_info_p)117 void i2c_cmd_stop(ls1c_i2c_info_t *i2c_info_p)
118 {
119 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_STOP);
120 return ;
121 }
122
123
124 /*
125 * ִ��д����
126 * @i2c_info_p i2cģ����Ϣ
127 */
i2c_cmd_write(ls1c_i2c_info_t * i2c_info_p)128 void i2c_cmd_write(ls1c_i2c_info_t *i2c_info_p)
129 {
130 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_WRITE);
131 return ;
132 }
133
134
135 /*
136 * ִ�ж�ack������Ͷ�ack�ź�
137 * @i2c_info_p i2cģ����Ϣ
138 */
i2c_cmd_read_ack(ls1c_i2c_info_t * i2c_info_p)139 void i2c_cmd_read_ack(ls1c_i2c_info_t *i2c_info_p)
140 {
141 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_READ_ACK);
142 return ;
143 }
144
145
146 /*
147 * ִ�ж�nack����,���Ͷ�nack�ź�
148 * @i2c_info_p i2cģ����Ϣ
149 */
i2c_cmd_read_nack(ls1c_i2c_info_t * i2c_info_p)150 void i2c_cmd_read_nack(ls1c_i2c_info_t *i2c_info_p)
151 {
152 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_READ_NACK);
153 return ;
154 }
155
156
157 /*
158 * �����ж�Ӧ���ź�
159 * @i2c_info_p i2cģ����Ϣ
160 */
i2c_cmd_iack(ls1c_i2c_info_t * i2c_info_p)161 void i2c_cmd_iack(ls1c_i2c_info_t *i2c_info_p)
162 {
163 i2c_cmd(i2c_info_p, LS1C_I2C_CMD_IACK);
164 return ;
165 }
166
167
168 /*
169 * ��ȡ״̬�Ĵ�����ֵ
170 * @i2c_info_p i2cģ����Ϣ
171 * @ret ״̬�Ĵ�����ֵ
172 */
i2c_get_status(ls1c_i2c_info_t * i2c_info_p)173 unsigned char i2c_get_status(ls1c_i2c_info_t *i2c_info_p)
174 {
175 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
176
177 return reg_read_8(i2c_base + LS1C_I2C_STATUS_OFFSET);
178 }
179
180
181 /*
182 * Poll the i2c status register until the specified bit is set.
183 * Returns 0 if timed out (100 msec).
184 * @i2c_info_p i2cģ����Ϣ
185 * @bit �Ĵ�����ijһλ
186 * @ret true or false
187 */
i2c_poll_status(ls1c_i2c_info_t * i2c_info_p,unsigned long bit)188 int i2c_poll_status(ls1c_i2c_info_t *i2c_info_p, unsigned long bit)
189 {
190 int loop_cntr = 20000;
191
192 do {
193 delay_us(1);
194 } while ((i2c_get_status(i2c_info_p) & bit) && (0 < --loop_cntr));
195
196 return (0 < loop_cntr);
197 }
198
199
200 /*
201 * ��ʼ��ָ��i2cģ��
202 * @i2c_info_p ij��i2cģ�����Ϣ
203 */
i2c_init(ls1c_i2c_info_t * i2c_info_p)204 void i2c_init(ls1c_i2c_info_t *i2c_info_p)
205 {
206 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
207 unsigned long i2c_clock = i2c_info_p->clock;
208 unsigned char ctrl = reg_read_8(i2c_base + LS1C_I2C_CONTROL_OFFSET);
209 unsigned long prescale = 0;
210
211 /* make sure the device is disabled */
212 ctrl = ctrl & ~(LS1C_I2C_CONTROL_EN | LS1C_I2C_CONTROL_IEN);
213 reg_write_8(ctrl, i2c_base + LS1C_I2C_CONTROL_OFFSET);
214
215 // ����ʱ��
216 i2c_clock = MIN(i2c_clock, LS1C_I2C_CLOCK_MAX); // ���������������
217 prescale = clk_get_apb_rate();
218 prescale = (prescale / (5 * i2c_clock)) - 1;
219 reg_write_8(prescale & 0xff, i2c_base + LS1C_I2C_PRER_LOW_OFFSET);
220 reg_write_8(prescale >> 8, i2c_base + LS1C_I2C_PRER_HIGH_OFFSET);
221
222 // ʹ��
223 i2c_cmd_iack(i2c_info_p);
224 ctrl = ctrl | LS1C_I2C_CONTROL_EN;
225 reg_write_8(ctrl, i2c_base + LS1C_I2C_CONTROL_OFFSET);
226
227 return ;
228 }
229
230
231 /*
232 * (�ٷ���һ���ֽ�����֮��)���մӻ����͵�ACK�ź�
233 * @i2c_info_p i2cģ����Ϣ
234 * @ret LS1C_I2C_ACK or LS1C_I2C_NACK
235 */
i2c_receive_ack(ls1c_i2c_info_t * i2c_info_p)236 ls1c_i2c_ack_t i2c_receive_ack(ls1c_i2c_info_t *i2c_info_p)
237 {
238 ls1c_i2c_ack_t ret = LS1C_I2C_NACK;
239
240 if (LS1C_I2C_STATUS_NACK & i2c_get_status(i2c_info_p))
241 {
242 ret = LS1C_I2C_NACK;
243 }
244 else
245 {
246 ret = LS1C_I2C_ACK;
247 }
248
249 return ret;
250 }
251
252
253 /*
254 * ��������
255 * @i2c_info_p i2cģ����Ϣ
256 * @buf ���ݻ���
257 * @len ���������ݵij���
258 */
i2c_receive_data(ls1c_i2c_info_t * i2c_info_p,unsigned char * buf,int len)259 ls1c_i2c_ret_t i2c_receive_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *buf, int len)
260 {
261 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
262 int i = 0;
263
264 for (i=0; i<len; i++)
265 {
266 // ��ʼ����
267 if (i != (len - 1))
268 i2c_cmd_read_ack(i2c_info_p);
269 else
270 i2c_cmd_read_nack(i2c_info_p);
271
272 // �ȴ���ֱ���������
273 if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP))
274 return LS1C_I2C_RET_TIMEOUT;
275
276 // ��ȡ���ݣ�������
277 *buf++ = reg_read_8(i2c_base + LS1C_I2C_DATA_OFFSET);
278 }
279
280 return LS1C_I2C_RET_OK;
281 }
282
283
284 /*
285 * ����START�źź͵�ַ
286 * @i2c_info_p i2cģ����Ϣ
287 * @slave_addr �ӻ���ַ
288 * @direction ���ݴ��䷽��(����д)
289 */
i2c_send_start_and_addr(ls1c_i2c_info_t * i2c_info_p,unsigned char slave_addr,ls1c_i2c_direction_t direction)290 ls1c_i2c_ret_t i2c_send_start_and_addr(ls1c_i2c_info_t *i2c_info_p,
291 unsigned char slave_addr,
292 ls1c_i2c_direction_t direction)
293 {
294 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
295 unsigned char data = 0;
296
297 // �ȴ�i2c���߿���
298 if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_BUSY))
299 return LS1C_I2C_RET_TIMEOUT;
300
301 // ����ַ�����ݼĴ���
302 data = (slave_addr << 1) | ((LS1C_I2C_DIRECTION_READ == direction) ? 1 : 0);
303 reg_write_8(data , i2c_base + LS1C_I2C_DATA_OFFSET);
304
305 // ��ʼ����
306 i2c_cmd_start(i2c_info_p);
307
308 // �ȴ���ֱ���������
309 if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP))
310 return LS1C_I2C_RET_TIMEOUT;
311
312 return LS1C_I2C_RET_OK;
313 }
314
315
316 /*
317 * ��������
318 * @i2c_info_p i2cģ����Ϣ
319 * @data �����͵�����
320 * @len ���������ݵij���
321 */
i2c_send_data(ls1c_i2c_info_t * i2c_info_p,unsigned char * data,int len)322 ls1c_i2c_ret_t i2c_send_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *data, int len)
323 {
324 void *i2c_base = i2c_get_base(i2c_info_p->I2Cx);
325 int i = 0;
326
327 for (i=0; i<len; i++)
328 {
329 // ��һ���ֽ�����д�����ݼĴ���
330 reg_write_8(*data++, i2c_base + LS1C_I2C_DATA_OFFSET);
331
332 // ��ʼ����
333 reg_write_8(LS1C_I2C_CMD_WRITE, i2c_base + LS1C_I2C_CMD_OFFSET);
334
335 // �ȴ���ֱ���������
336 if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP))
337 return LS1C_I2C_RET_TIMEOUT;
338
339 // ��ȡӦ���ź�
340 if (LS1C_I2C_ACK != i2c_receive_ack(i2c_info_p))
341 return len;
342 }
343
344 return LS1C_I2C_RET_OK;
345 }
346
347
348
349 /*
350 * ����STOP�ź�
351 * @i2c_info_p i2cģ����Ϣ
352 */
i2c_send_stop(ls1c_i2c_info_t * i2c_info_p)353 void i2c_send_stop(ls1c_i2c_info_t *i2c_info_p)
354 {
355 i2c_cmd_stop(i2c_info_p);
356 return ;
357 }
358
359
360