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