tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / i2c / sc8825_i2c.c
1 /******************************************************************************\r
2  ** File Name:      i2c_drv.c                                                 *\r
3  ** Author:         Richard Yang                                              *\r
4  ** DATE:           01/16/2001                                                *\r
5  ** Copyright:      2002 Spreatrum, Incoporated. All Rights Reserved.         *\r
6  ** Description:    This file defines the basic operation interfaces of       *\r
7  **                 serrial device. It manages create, send, receive          *\r
8  **                 interface of serrial port.                                *\r
9  ******************************************************************************\r
10 \r
11  ******************************************************************************\r
12  **                        Edit History                                       *\r
13  ** ------------------------------------------------------------------------- *\r
14  ** DATE           NAME             DESCRIPTION                               *\r
15  ** 01/16/2001     Richard.Yang     Create.                                   *\r
16  ** 04/02/2002     Lin.Liu            Code                                      *\r
17  ** 04/22/2002     Lin.liu          Set CPC_ZD_WPU after change clock.        *\r
18  ** 04/23/2002     Lin.liu          1. Remove i2c_clk to i2c_drv.h            * \r
19  **                                 2. Remove i2c_inited flag                 *\r
20  ******************************************************************************/\r
21 \r
22 /**---------------------------------------------------------------------------*\r
23  **                         Dependencies                                      *\r
24  **---------------------------------------------------------------------------*/\r
25 #include <asm/arch/sci_types.h>\r
26 #include <asm/arch/os_api.h>\r
27 #include <asm/arch/i2c_phy.h>\r
28 #include <asm/arch/i2c_reg_v0.h>\r
29 #include <asm/arch/chip_drvapi.h>\r
30 #include <asm/arch/chip_plf_export.h>\r
31 #include <asm/arch/sc8810_reg_global.h>\r
32 #include <asm/arch/sc8810_reg_base.h>\r
33 //#define I2C_BASE              I2C0_BASE\r
34 \r
35 //#include "dcam_fpga_misc.h"\r
36 \r
37 #ifndef TIGER_REG\r
38 #define TIGER_REG\r
39 #endif\r
40 \r
41 /**---------------------------------------------------------------------------*\r
42  **                         Debugging Flag                                    *\r
43  **---------------------------------------------------------------------------*/\r
44 /**---------------------------------------------------------------------------*\r
45  **                         Compiler Flag                                     *\r
46  **---------------------------------------------------------------------------*/\r
47 #ifdef   __cplusplus\r
48     extern   "C" \r
49     {\r
50 #endif\r
51 \r
52 \r
53 \r
54 /**---------------------------------------------------------------------------*\r
55  **                            Macro Define\r
56  **---------------------------------------------------------------------------*/\r
57 \r
58 #define I2C_TIMEOUT_FACTOR  500000  //the critical value is 10000\r
59 \r
60 #define ARM_CLK_13M         13000000\r
61 #define ARM_CLK_24M         24000000\r
62 \r
63 \r
64 #define I2C_READ_BIT        0x1\r
65 \r
66 //#define I2C_USE_INT\r
67 \r
68 #ifndef I2C_USE_INT \r
69 \r
70 #define I2C_WAIT_INT                                                  \\r
71 {                                                                     \\r
72     timetick = SYSTEM_CURRENT_CLOCK;                                  \\r
73     while(!(ptr->ctl & I2CCTL_INT))                                   \\r
74     {                                                                 \\r
75         if((SYSTEM_CURRENT_CLOCK - timetick) >= g_i2c_timeout)        \\r
76         {                                                             \\r
77             if(ERR_I2C_NONE == ret_value)                             \\r
78             {                                                         \\r
79                 ret_value = ERR_I2C_INT_TIMEOUT;                      \\r
80             }                                                         \\r
81             break;                                                    \\r
82         }                                                             \\r
83                                                                       \\r
84     }                                                                 \\r
85                                                                       \\r
86 }\r
87 \r
88 #else\r
89 \r
90 #define I2C_WAIT_INT                                                  \\r
91 {                                                                     \\r
92     timetick = SYSTEM_CURRENT_CLOCK;                                  \\r
93     while (g_wait_i2c_int_flag)                                       \\r
94     {                                                                 \\r
95         if ((SYSTEM_CURRENT_CLOCK - timetick) >= g_i2c_timeout)       \\r
96         {                                                             \\r
97             if(ERR_I2C_NONE == ret_value)                             \\r
98             {                                                         \\r
99                 ret_value = ERR_I2C_INT_TIMEOUT;                      \\r
100             }                                                         \\r
101             break;                                                    \\r
102         }                                                             \\r
103     }                                                                 \\r
104     g_wait_i2c_int_flag = 1;                                          \\r
105 }\r
106 \r
107 #endif \r
108        \r
109 #define I2C_WAIT_BUSY                                                 \\r
110 {                                                                     \\r
111     timetick = SYSTEM_CURRENT_CLOCK;                                  \\r
112     while(ptr->cmd & I2CCMD_BUS)                                      \\r
113     {                                                                 \\r
114         if ((SYSTEM_CURRENT_CLOCK - timetick) >= g_i2c_timeout)       \\r
115         {                                                             \\r
116             if(ERR_I2C_NONE == ret_value)                             \\r
117             {                                                         \\r
118                 ret_value = ERR_I2C_BUSY_TIMEOUT;                     \\r
119             }                                                         \\r
120             break;                                                    \\r
121         }                                                             \\r
122     }                                                                 \\r
123                                                                       \\r
124 }\r
125        \r
126 #define I2C_WAIT_ACK                                                  \\r
127 {                                                                     \\r
128     timetick = SYSTEM_CURRENT_CLOCK;                                  \\r
129     while(ptr->cmd & I2CCMD_ACK)                                      \\r
130     {                                                                 \\r
131         if ((SYSTEM_CURRENT_CLOCK - timetick) >= g_i2c_timeout)       \\r
132         {                                                             \\r
133             if(ERR_I2C_NONE == ret_value)                             \\r
134             {                                                         \\r
135                 ret_value = ERR_I2C_ACK_TIMEOUT;                      \\r
136             }                                                         \\r
137             break;                                                    \\r
138         }                                                             \\r
139     }                                                                 \\r
140 }\r
141 \r
142 #ifndef I2C_USE_INT\r
143 \r
144 #define I2C_CLEAR_INT                                                 \\r
145 {                                                                     \\r
146     I2C_WAIT_BUSY                                                     \\r
147     CHIP_REG_OR(I2C_CMD, I2CCMD_INT_ACK);                               \\r
148 }\r
149 \r
150 #else\r
151 \r
152 #define I2C_CLEAR_INT  \r
153 \r
154 #endif\r
155 \r
156 void ms_delay(uint32 ticks)\r
157 {\r
158         int i;\r
159         for(i=0; i<10*ticks; i++);\r
160 }       \r
161 /**---------------------------------------------------------------------------*\r
162  **                            Global Variables\r
163  **---------------------------------------------------------------------------*/\r
164 volatile BOOLEAN    g_wait_i2c_int_flag;\r
165 volatile BOOLEAN    g_i2c_open_flag=FALSE;\r
166 volatile uint32     g_i2c_timeout = 10; //unit is ms\r
167 \r
168 /**---------------------------------------------------------------------------*\r
169  **                      Function  Definitions\r
170  **---------------------------------------------------------------------------*/\r
171 \r
172 uint32 CHIP_GetAPBClk(void)\r
173 {\r
174     return ARM_CLK_26M;\r
175 }\r
176 \r
177 /*********************************************************************/\r
178 //  Description: i2c interrupt service \r
179 //  Input:\r
180 //      param         not use\r
181 //  Return:\r
182 //      None\r
183 //    Note: \r
184 //      None       \r
185 /*********************************************************************/\r
186 PUBLIC void I2C_Handler(uint32 param)\r
187 {\r
188     param = param; // avoid compiler warning\r
189 \r
190     /* set i2c flag  */    \r
191     g_wait_i2c_int_flag = FALSE;\r
192     \r
193     while((*(volatile uint32*)(I2C_CMD)) & I2CCMD_BUS);\r
194     \r
195     /* clear i2c int  */\r
196     CHIP_REG_OR(I2C_CMD, I2CCMD_INT_ACK);    \r
197 }\r
198 /*********************************************************************/\r
199 //  Description: i2c set SCL clock\r
200 //  Input:\r
201 //      freq     I2C SCL's frequency to be set\r
202 //  Return:\r
203 //      ERR_I2C_NONE    successfully\r
204 //    Note: \r
205 //      None       \r
206 /*********************************************************************/\r
207 PUBLIC ERR_I2C_E I2C_SetSCLclk(uint32 freq)\r
208 {\r
209     uint32 APB_clk,i2c_dvd;\r
210     \r
211     volatile I2C_CTL_REG_T *ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
212 \r
213     SCI_ASSERT(freq > 0);\r
214     SCI_ASSERT(g_i2c_open_flag);\r
215 \r
216     APB_clk= CHIP_GetAPBClk();\r
217     i2c_dvd=APB_clk/(4*freq)-1;\r
218 \r
219     ptr->div0=(uint16)(i2c_dvd & 0xffff);\r
220     ptr->div1=(uint16)(i2c_dvd>>16);\r
221 \r
222     g_i2c_timeout = I2C_TIMEOUT_FACTOR / (freq);\r
223     \r
224     if(g_i2c_timeout < 2)\r
225         g_i2c_timeout = 2;\r
226     //g_i2c_timeout will be changed according I2C frequency\r
227     \r
228     return ERR_I2C_NONE;\r
229      \r
230       \r
231 }\r
232 /*********************************************************************/\r
233 //  Description: i2c init fuction \r
234 //  Input:\r
235 //      freq     I2C SCL's frequency\r
236 //  Return:\r
237 //      ERR_I2C_NONE    successfully\r
238 //    Note: \r
239 //      None       \r
240 /*********************************************************************/\r
241 PUBLIC ERR_I2C_E I2C_Init(uint32 freq)\r
242 {    \r
243     /*SC8810 use IIC1 for sensor init, but befoe SC8810 all chip use\r
244     IIC0 for sensor init. IIC1 use bit29 for Clock enable.\r
245     */\r
246     volatile I2C_CTL_REG_T *ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
247 \r
248     freq*=1000;\r
249     SCI_ASSERT (freq > 0);\r
250 \r
251     g_wait_i2c_int_flag = TRUE;\r
252     g_i2c_open_flag=TRUE;\r
253 \r
254     // gen0, enable i2c device.\r
255 #if 0\r
256         CHIP_REG_OR(GR_GEN0, APB_I2C1_EB); //GEN0_I2C1_EN\r
257 #else\r
258     CHIP_REG_OR(GR_GEN0, GEN0_I2C_EN); //GEN0_I2C0_EN\r
259 #endif\r
260 \r
261     ptr->rst = BIT_0;//why reset\r
262     ptr->ctl &= ~(I2CCTL_EN);//you must first disable i2c module then change clock  \r
263     ptr->ctl &= ~(I2CCTL_IE);\r
264     ptr->ctl &= ~(I2CCTL_CMDBUF_EN);\r
265 \r
266     I2C_SetSCLclk(freq);\r
267 \r
268     CHIP_REG_OR(I2C_CTL, (I2CCTL_IE | I2CCTL_EN));\r
269 \r
270      //Clear I2C int\r
271     CHIP_REG_OR(I2C_CMD, I2CCMD_INT_ACK); \r
272    \r
273     return ERR_I2C_NONE;\r
274     \r
275 #if 0    \r
276     volatile I2C_CTL_REG_T *ptr = (I2C_CTL_REG_T *)I2C_BASE;\r
277 \r
278     freq*=1000;\r
279     SCI_ASSERT (freq > 0);\r
280 \r
281     g_wait_i2c_int_flag = TRUE;\r
282     g_i2c_open_flag=TRUE;\r
283 \r
284     // gen0, enable i2c device.\r
285     CHIP_REG_OR(GR_GEN0, GEN0_I2C_EN);\r
286     \r
287     ptr->rst = BIT_0;//why reset\r
288     ptr->ctl &= ~(I2CCTL_EN);//you must first disable i2c module then change clock  \r
289     ptr->ctl &= ~(I2CCTL_IE);\r
290     ptr->ctl &= ~(I2CCTL_CMDBUF_EN);\r
291 \r
292     I2C_SetSCLclk(freq);\r
293 \r
294     CHIP_REG_OR(I2C_CTL, (I2CCTL_IE | I2CCTL_EN));\r
295 \r
296      //Clear I2C int\r
297     CHIP_REG_OR(I2C_CMD, I2CCMD_INT_ACK); \r
298    \r
299     return ERR_I2C_NONE;\r
300 #endif    \r
301 }\r
302 /*********************************************************************/\r
303 //  Description: get i2c SCL clock\r
304 //  Input:\r
305 //      None\r
306 //  Return:\r
307 //      the freq of i2c SCL clock\r
308 //    Note: \r
309 //      None       \r
310 /*********************************************************************/\r
311 PUBLIC uint32 I2C_GetSCLclk()\r
312 {\r
313     uint32 APB_clk,i2c_dvd,freq;\r
314     \r
315     volatile I2C_CTL_REG_T *ptr = (I2C_CTL_REG_T *)I2C_BASE;\r
316 \r
317     SCI_ASSERT(g_i2c_open_flag);\r
318 \r
319     APB_clk= CHIP_GetAPBClk();\r
320 \r
321     i2c_dvd=((ptr->div1)<<16)|(ptr->div0);\r
322 \r
323     freq=APB_clk/(4*(i2c_dvd+1));\r
324 \r
325 \r
326     return freq;\r
327 \r
328 }\r
329 /*********************************************************************/\r
330 //  Description: Write a command to a slave device\r
331 //  Input:\r
332 //      addr     the slave device's address\r
333 //      command  the command to be set into the slave device's address\r
334 //        ack_en     Enable/Disable check the slave device rsp ACK\r
335 //  Return:\r
336 //      ERR_I2C_NONE    successfully\r
337 //    Note: \r
338 //      None       \r
339 /*********************************************************************/\r
340 PUBLIC ERR_I2C_E I2C_WriteCmd(uint8 addr,uint8 command, BOOLEAN ack_en)\r
341 {\r
342     volatile uint32 timetick = 0; \r
343     volatile uint32 cmd = 0;\r
344     volatile I2C_CTL_REG_T * ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
345     uint32   ret_value = ERR_I2C_NONE;\r
346 \r
347     SCI_ASSERT(g_i2c_open_flag);\r
348     SCI_ASSERT(g_i2c_timeout > 0);\r
349     \r
350     cmd = ((uint32)addr)<<8;\r
351     cmd = cmd | I2CCMD_START | I2CCMD_WRITE;//send device address\r
352     ptr->cmd = cmd; \r
353 \r
354     I2C_WAIT_INT\r
355     \r
356     I2C_CLEAR_INT\r
357     \r
358     //check ACK\r
359     if(ack_en)\r
360     {\r
361         I2C_WAIT_ACK\r
362     }\r
363 \r
364     cmd = ((uint32)command)<<8;\r
365     cmd = cmd | I2CCMD_WRITE | I2CCMD_STOP;//send command\r
366     ptr->cmd = cmd; \r
367 \r
368     I2C_WAIT_INT\r
369        \r
370     I2C_CLEAR_INT  \r
371 \r
372     //check ACK\r
373     if(ack_en)\r
374     {\r
375         I2C_WAIT_ACK\r
376     }\r
377 \r
378     return ERR_I2C_NONE;\r
379             \r
380 }\r
381 \r
382 /*********************************************************************/\r
383 //  Description: Write a data to a slave device\r
384 //  Input:\r
385 //      addr     the slave device's address\r
386 //      command  the command to be set into the slave device's address\r
387 //        ack_en     Enable/Disable check the slave device rsp ACK\r
388 //  Return:\r
389 //      ERR_I2C_NONE    successfully\r
390 //    Note: \r
391 //      None       \r
392 /*********************************************************************/\r
393 PUBLIC ERR_I2C_E I2C_WriteData(uint8 addr,uint8 data, BOOLEAN ack_en)\r
394 {\r
395     volatile uint32 timetick = 0; \r
396     volatile uint32 cmd = 0;\r
397     volatile I2C_CTL_REG_T * ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
398     uint32   ret_value = ERR_I2C_NONE;\r
399 \r
400     SCI_ASSERT(g_i2c_open_flag);\r
401     SCI_ASSERT(g_i2c_timeout > 0);\r
402     \r
403     cmd = ((uint32)addr)<<8;\r
404     cmd = cmd | I2CCMD_START | I2CCMD_WRITE;//send device address\r
405     ptr->cmd = cmd; \r
406 \r
407     I2C_WAIT_INT\r
408     \r
409     I2C_CLEAR_INT\r
410     \r
411     //check ACK\r
412     if(ack_en)\r
413     {\r
414         I2C_WAIT_ACK\r
415     }\r
416 \r
417     data = ((uint32)data)<<8;\r
418     data = data | I2CCMD_WRITE | I2CCMD_STOP;//send command\r
419     ptr->cmd = data; \r
420 \r
421     I2C_WAIT_INT\r
422        \r
423     I2C_CLEAR_INT  \r
424 \r
425     //check ACK\r
426     if(ack_en)\r
427     {\r
428         I2C_WAIT_ACK\r
429     }\r
430 \r
431     return ERR_I2C_NONE;\r
432             \r
433 }\r
434 /*********************************************************************/\r
435 //  Description: read a command from the slave device\r
436 //  Input:\r
437 //      addr     the slave device's address\r
438 //      pCmd     the command's pointer\r
439 //        ack_en     Enable/Disable check the slave device rsp ACK\r
440 //  Return:\r
441 //      ERR_I2C_NONE    successfully\r
442 //    Note: \r
443 //      None       \r
444 /*********************************************************************/\r
445 PUBLIC ERR_I2C_E I2C_ReadCmd(uint8 addr,uint8 *pCmd, BOOLEAN ack_en)\r
446 {\r
447     volatile uint32 timetick = 0; \r
448     volatile uint32 cmd = 0;\r
449     volatile I2C_CTL_REG_T * ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
450     uint32   ret_value = ERR_I2C_NONE;\r
451     \r
452     SCI_ASSERT(NULL != pCmd);\r
453     SCI_ASSERT(g_i2c_open_flag);\r
454     SCI_ASSERT(g_i2c_timeout > 0);\r
455 \r
456     cmd = ((uint32)(addr|I2C_READ_BIT))<<8;\r
457     cmd = cmd | I2CCMD_START | I2CCMD_WRITE;//send device address\r
458     ptr->cmd = cmd; \r
459 \r
460     I2C_WAIT_INT\r
461            \r
462     I2C_CLEAR_INT  \r
463 \r
464     //check ACK\r
465     if(ack_en)\r
466     {\r
467         I2C_WAIT_ACK\r
468     }\r
469 \r
470     cmd = I2CCMD_READ | I2CCMD_STOP | I2CCMD_TX_ACK;\r
471     ptr->cmd = cmd;\r
472      \r
473     I2C_WAIT_INT\r
474        \r
475     I2C_CLEAR_INT  \r
476 \r
477 \r
478     *pCmd=(uint8)((ptr->cmd)>>8);\r
479 \r
480     return ERR_I2C_NONE;\r
481 }\r
482 /*********************************************************************/\r
483 //  Description: Write the command array into the slave device \r
484 //  Input:\r
485 //      addr     the slave device's address\r
486 //      pCmd     the command array's pointer\r
487 //      len      the length of the command array\r
488 //        ack_en     Enable/Disable check the slave device rsp ACK\r
489 //  Return:\r
490 //      ERR_I2C_NONE    successfully\r
491 //    Note: \r
492 //      None       \r
493 /*********************************************************************/\r
494     uint32   ret_value = ERR_I2C_NONE;\r
495     volatile uint32 timetick = 0; \r
496 PUBLIC ERR_I2C_E I2C_WriteCmdArr(uint8 addr, uint8 *pCmd, uint32 len, BOOLEAN ack_en)\r
497 {\r
498     volatile uint32 curtime = 0;        \r
499     volatile uint32 i = 0;\r
500     volatile uint32 cmd = 0;\r
501     volatile I2C_CTL_REG_T * ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
502     \r
503     SCI_ASSERT(NULL != pCmd);\r
504     SCI_ASSERT(g_i2c_open_flag);\r
505     SCI_ASSERT(g_i2c_timeout > 0);\r
506     \r
507     cmd = ((uint32)addr)<<8;\r
508     cmd = cmd | I2CCMD_START | I2CCMD_WRITE ;//send device address 0x9824\r
509     ptr->cmd = cmd; \r
510 \r
511     I2C_WAIT_INT                \r
512     \r
513     I2C_CLEAR_INT   \r
514     \r
515     //check ACK\r
516     if(ack_en)\r
517     {\r
518         I2C_WAIT_ACK\r
519     }\r
520 \r
521     for(i=0;i<len;i++)\r
522     {\r
523         cmd = ((uint32)pCmd[i])<<8;\r
524         if(i== (len-1))     \r
525             cmd = cmd | I2CCMD_WRITE | I2CCMD_STOP;//send command\r
526         else\r
527             cmd = cmd | I2CCMD_WRITE ;\r
528 \r
529         ptr->cmd = cmd; \r
530 \r
531         I2C_WAIT_INT\r
532            \r
533         I2C_CLEAR_INT    \r
534 \r
535         //check ACK\r
536         if(ack_en)\r
537         {\r
538             I2C_WAIT_ACK\r
539         }\r
540 \r
541     }\r
542 \r
543     return ret_value;\r
544 }\r
545 /*********************************************************************/\r
546 //  Description: Read a command array from the slave device \r
547 //  Input:\r
548 //      addr     the slave device's address\r
549 //      pCmd     the command array's pointer\r
550 //      len      the length of command array\r
551 //        ack_en     Enable/Disable check the slave device rsp ACK\r
552 //  Return:\r
553 //      ERR_I2C_NONE    successfully\r
554 //    Note: \r
555 //      None       \r
556 /*********************************************************************/\r
557 PUBLIC ERR_I2C_E I2C_ReadCmdArr(uint8 addr, uint8 *pCmd, uint32 len,BOOLEAN ack_en )\r
558 {\r
559     volatile uint32 timetick = 0; \r
560     volatile uint32 i = 0;\r
561     volatile uint32 cmd = 0;\r
562     volatile I2C_CTL_REG_T * ptr = (volatile I2C_CTL_REG_T *)I2C_BASE;\r
563     uint32   ret_value = ERR_I2C_NONE;\r
564     \r
565     SCI_ASSERT(NULL !=pCmd );\r
566     SCI_ASSERT(g_i2c_open_flag);\r
567     SCI_ASSERT(g_i2c_timeout > 0);\r
568 \r
569     cmd = ((uint32)(addr|I2C_READ_BIT))<<8;\r
570     cmd = cmd | I2CCMD_START | I2CCMD_WRITE;//send device address\r
571     ptr->cmd = cmd; \r
572 \r
573     I2C_WAIT_INT\r
574            \r
575     I2C_CLEAR_INT\r
576     \r
577     //check ACK\r
578     if(ack_en)\r
579     {\r
580         I2C_WAIT_ACK\r
581     }\r
582 \r
583     for(i=0;i<len;i++)\r
584     {\r
585         if(i<len-1)\r
586             cmd = I2CCMD_READ;  // I2CCMD_READ|I2CCMD_TX_ACK;\r
587         else\r
588             cmd = I2CCMD_READ|I2CCMD_STOP|I2CCMD_TX_ACK;\r
589 \r
590         ptr->cmd = cmd;\r
591 \r
592         I2C_WAIT_INT\r
593                    \r
594         I2C_CLEAR_INT   \r
595 \r
596         pCmd[i] = (uint8)((ptr->cmd)>>8);\r
597     }\r
598 \r
599     return ERR_I2C_NONE;\r
600 }\r
601 \r
602 \r
603 /**---------------------------------------------------------------------------*\r
604  **                         Compiler Flag                                     *\r
605  **---------------------------------------------------------------------------*/\r
606 \r
607 \r
608 #ifdef   __cplusplus\r
609     } \r
610 #endif\r
611 \r
612 /*  End Of File */\r