blob: 889cd1d3c6cb1d72c84d00a21cdd6a3da3a4ed6f [file] [log] [blame]
rjw6c1fd8f2022-11-30 14:33:01 +08001/*****************************************************************************
2* Copyright Statement:
3* --------------------
4* This software is protected by Copyright and the information contained
5* herein is confidential. The software may not be copied and the information
6* contained herein may not be used or disclosed except with the written
7* permission of MediaTek Inc. (C) 2005
8*
9* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
10* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
11* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
12* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
13* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
14* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
15* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
16* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
17* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
18* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
19* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
20* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
21*
22* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
23* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
24* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
25* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
26* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
27*
28* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
29* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
30* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
31* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
32* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
33*
34*****************************************************************************/
35
36/*****************************************************************************
37 *
38 * Filename:
39 * ---------
40 * drv_i2c.c
41 *
42 *
43 * Description:
44 * ------------
45 * I2C Driver
46 *
47 * Author:
48 * -------
49 * -------
50 *
51 *============================================================================
52 * HISTORY
53 * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
54 *------------------------------------------------------------------------------
55 * removed!
56 * removed!
57 * removed!
58 *
59 * removed!
60 * removed!
61 * removed!
62 *
63 * removed!
64 * removed!
65 * removed!
66 *
67 * removed!
68 * removed!
69 * removed!
70 *
71 * removed!
72 * removed!
73 * removed!
74 * removed!
75 *------------------------------------------------------------------------------
76 * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
77 *============================================================================
78 *****************************************************************************/
79#include "drv_comm.h"
80#include "reg_base.h"
81#include "drv_i2c.h" //*/ the new sccb_v2.h should be named i2c.h /*//
82#include "drvpdn.h"
83
84#include "dcl_i2c_owner.h"
85#include "kal_general_types.h"
86#include "kal_public_api.h"
87#include "drvpdn_inline.h"
88#include <ex_item.h>
89#include <ex_public.h>
90
91#if (!defined(DRV_I2C_OFF))
92#if defined(__MD95__)
93#define I2C_POWER_OFF() do{PDN_SET(PDN_I2C_BCLK);}while(0) /* Power off I2C */
94#define I2C_POWER_ON() do{PDN_CLR(PDN_I2C_BCLK);}while(0) /* Power on I2C */
95#else
96#define I2C_POWER_OFF()
97#define I2C_POWER_ON()
98#endif
99/// I2C internal global variables
100i2c_handle_struct i2c_handle[DCL_I2C_NUM_OF_OWNER];
101i2c_status_struct dcl_i2c_status;
102kal_bool i2c_lock_status = KAL_FALSE;
103kal_spinlockid i2c_lock_id = 0;
104
105
106//*/ abstract the HW register config API /*//
107//called in i2c_write -> dcl_i2c_hw_cfg (owner, I2C_TRANSACTION_WRITE, para, datalen, NULL, 0, 1);
108//called in i2c_read -> dcl_i2c_hw_cfg (owner, I2C_TRANSACTION_READ, NULL, 0, para, datalen, 1);
109//called in i2c_cont_write -> dcl_i2c_hw_cfg (owner, I2C_TRANSACTION_CONT_WRITE, para, datalen_in_transfer, NULL, 0, transfer_num);
110//called in i2c_cont_read -> dcl_i2c_hw_cfg (owner, I2C_TRANSACTION_CONT_READ, NULL, 0, para, datalen_in_transfer, transfer_num);
111//called in i2c_write_and_read -> dcl_i2c_hw_cfg (owner, I2C_TRANSACTION_WRITE_AND_READ, write_buffer, write_len, read_buffer, read_len, 2);
112void dcl_i2c_hw_cfg (DCL_I2C_OWNER owner, I2C_TRANSACTION_TYPE type, kal_uint8* write_buffer, kal_uint32 write_len, kal_uint8* read_buffer, kal_uint32 read_len, kal_uint32 transfer_num)
113{
114 i2c_handle_struct* handle=&i2c_handle[owner];
115 i2c_config_struct* config=&handle->i2c_config;
116 kal_uint32 count_write, count_read, i;
117
118 if (read_len>DRV_I2C_FIFO_DEPTH || write_len>DRV_I2C_FIFO_DEPTH) //if u want a transcation with len>8, please enable DMA.
119 {
120 ASSERT(0);
121 }
122 count_write = write_len*transfer_num;
123 count_read = read_len*transfer_num;
124
125 CLEAR_I2C_FIFO;
126 CLEAR_I2C_STA;
127 DISABLE_I2C_INT;
128
129 SET_I2C_STEP_CNT_DIV(handle->fs_step_cnt_div);
130 SET_I2C_SAMPLE_CNT_DIV(handle->fs_sample_cnt_div);
131
132 SET_I2C_TRANSACTION_LENGTH(transfer_num);
133
134 if (handle->i2c_config.transaction_mode == I2C_TRANSACTION_FAST_MODE)
135 {
136 SET_I2C_FAST_MODE;
137 SET_I2C_ST_BETWEEN_TRANSFER;
138 if (config->delay_len>0)
139 {
140 SET_I2C_DELAY_LENGTH(config->delay_len-1);
141 }
142 if ((config->delay_len == 0)&&((type == I2C_TRANSACTION_CONT_WRITE)||(type == I2C_TRANSACTION_CONT_READ)))
143 {
144 SET_I2C_RS_BETWEEN_TRANSFER;
145 }
146 }
147 else if (handle->i2c_config.transaction_mode == I2C_TRANSACTION_HIGH_SPEED_MODE)
148 {
149 SET_I2C_HS_STEP_CNT_DIV(handle->hs_step_cnt_div);
150 SET_I2C_HS_SAMPLE_CNT_DIV(handle->hs_sample_cnt_div);
151 SET_I2C_HS_MODE;
152 SET_I2C_RS_BETWEEN_TRANSFER;
153 }
154
155 DISABLE_I2C_DIR_CHANGE;
156 DISABLE_I2C_DMA_TRANSFER;
157
158 if ((type == I2C_TRANSACTION_WRITE)||(type == I2C_TRANSACTION_CONT_WRITE))
159 {
160 SET_I2C_SLAVE_ADDRESS(config->slave_address,I2C_WRITE_BIT);
161 SET_I2C_TRANSFER_LENGTH(write_len);
162 dcl_i2c_status.number_of_read=0;
163
164 for (i=0;i<count_write;i++)
165 {
166 DRV_I2C_WriteReg16(REG_I2C_DATA_PORT, *(write_buffer+i));
167 }
168 }
169 else if ((type == I2C_TRANSACTION_READ)||(type == I2C_TRANSACTION_CONT_READ))
170 {
171 SET_I2C_SLAVE_ADDRESS(config->slave_address,I2C_READ_BIT);
172 SET_I2C_TRANSFER_LENGTH(read_len);
173 dcl_i2c_status.number_of_read = count_read;
174 dcl_i2c_status.read_buffer=read_buffer;
175 }
176 else if (type == I2C_TRANSACTION_WRITE_AND_READ)
177 {
178 SET_I2C_SLAVE_ADDRESS(config->slave_address,I2C_WRITE_BIT);
179 SET_I2C_TRANSFER_LENGTH(write_len);
180 SET_I2C_AUX_TRANSFER_LENGTH(read_len);
181 ENABLE_I2C_DIR_CHANGE;
182 SET_I2C_RS_BETWEEN_TRANSFER;
183
184 dcl_i2c_status.number_of_read = read_len;
185 dcl_i2c_status.read_buffer=read_buffer;
186 for (i=0;i<write_len;i++)
187 {
188 DRV_I2C_WriteReg16(REG_I2C_DATA_PORT, (*(write_buffer+i)));
189 }
190 }
191 START_I2C_TRANSACTION;
192}
193
194
195void _dcl_i2c_status_handler(kal_uint32 sta)
196{
197 kal_uint32 i;
198 kal_uint8* read_buffer=dcl_i2c_status.read_buffer;
199 kal_uint32 number_of_read=dcl_i2c_status.number_of_read;
200 i2c_handle_struct* handle=&i2c_handle[dcl_i2c_status.owner];
201
202 if (sta == I2C_TRANSAC_COMPLETE) //This transaction is done now
203 {
204 for (i=0;i<number_of_read;i++)
205 {
206 read_buffer[i]=(DRV_I2C_ReadReg16(REG_I2C_DATA_PORT) & 0xff); //copy the read data to the previous transcation owner
207 }
208 handle->transaction_result = I2C_TRANSACTION_COMPLETE;
209 }
210 else
211 {
212 if (sta & I2C_TRANSAC_ACK_ERR)
213 handle->transaction_result = I2C_TRANSACTION_ACKERR;
214 else if (sta & I2C_HS_NACK_ERR)
215 handle->transaction_result = I2C_TRANSACTION_HS_NACKERR;
216 else //if got this, check register INTR_STAT to debug
217 handle->transaction_result = I2C_TRANSACTION_FAIL;
218 }
219 dcl_i2c_status.state=I2C_READY_STATE;
220}
221
222void _dcl_i2c_lisr(kal_uint32 vector)
223{
224 kal_uint32 savedMask;
225 kal_uint32 sta;
226 //test lisr executive time
227 //kal_uint32 start_qbit,end_qbit;//
228
229 //start_qbit = HW_TDMA_GET_TQCNT();//
230
231 savedMask = SaveAndSetIRQMask();
232
233 sta = DRV_I2C_ReadReg16(REG_I2C_INT_STA); //sta=REG_I2C_INT_STA;
234
235 {
236 _dcl_i2c_status_handler(sta);
237 }
238
239 RestoreIRQMask(savedMask);
240 //end_qbit = HW_TDMA_GET_TQCNT();//
241}
242
243
244void dcl_i2c_init(void)
245{
246 if(dcl_i2c_status.state != I2C_IDLE_STATE)
247 {
248 return;
249 }
250
251 dcl_i2c_status.state=I2C_READY_STATE;
252 I2C_POWER_ON();
253
254 SET_I2C_HW_MODE;
255 ENABLE_I2C_ACK_ERR_DET; //Always enable ack error detection
256 ENABLE_I2C_NAKERR_DET; //Always enable nack error detection
257
258 // create mutex
259 if(i2c_lock_status == KAL_FALSE && !INT_QueryExceptionStatus())
260 {
261 i2c_lock_id = kal_create_spinlock("DRV_I2C");
262 i2c_lock_status = KAL_TRUE;
263 }
264 MD_TRC(I2C_INIT_MSG,__FUNCTION__);
265}
266
267void dcl_i2c_deinit(void)
268{
269 RESET_I2C;
270 kal_mem_set(&dcl_i2c_status,0, sizeof(i2c_status_struct));
271 MD_TRC(I2C_DEINIT_MSG,__FUNCTION__);
272 I2C_POWER_OFF();
273}
274
275
276//----------------------------I2C internal arbiteration------------------------------
277//--When return from this function, I bit is turned off!!--
278kal_uint32 dcl_i2c_wait_transaction_complete_and_lock(DCL_I2C_OWNER owner)
279{
280 if (!(kal_if_lisr()))
281 {
282 while(1)
283 {
284 if (dcl_i2c_status.state==I2C_READY_STATE)
285 {
286 kal_take_spinlock(i2c_lock_id, KAL_INFINITE_WAIT);
287 dcl_i2c_status.state=I2C_BUSY_STATE; //Lock it
288 dcl_i2c_status.owner=owner;
289 kal_give_spinlock(i2c_lock_id);
290 return 0;//will restore it at: dcl_i2c_wait_transaction_complete
291 }
292 else if (i2c_handle[owner].i2c_config.get_handle_wait==KAL_FALSE)
293 {
294 return 0;
295 }
296
297 }//end of while
298 }
299 else
300 {
301 if (dcl_i2c_status.state!=I2C_READY_STATE)
302 {
303 ASSERT(0);
304 }
305
306 dcl_i2c_status.state=I2C_BUSY_STATE; //Lock it
307 dcl_i2c_status.owner=owner;
308 }
309
310 return 0;
311}
312
313
314
315void dcl_i2c_wait_transaction_complete(kal_uint32 savedMask)
316{
317 kal_uint32 sta=0,timer=0;
318 kal_uint32 i=0;
319 kal_uint8* read_buffer=dcl_i2c_status.read_buffer;
320 kal_uint32 number_of_read=dcl_i2c_status.number_of_read;
321 i2c_handle_struct* handle=&i2c_handle[dcl_i2c_status.owner];
322
323 timer = 10000;
324 do
325 {
326 sta = DRV_I2C_ReadReg16(REG_I2C_INT_STA);
327 timer--;
328 } while((!(sta & I2C_TRANSAC_COMPLETE)) && (timer!=0));
329
330 if(timer == 0){
331 MD_TRC(I2C_TRANSACTION_TIMETOUT_MSG,);
332 handle->transaction_result = I2C_TRANSACTION_FAIL;
333 return;
334 }
335
336 if (sta == I2C_TRANSAC_COMPLETE) //This transaction is done now
337 {
338 for (i=0;i<number_of_read;i++)
339 {
340 read_buffer[i]=(DRV_I2C_ReadReg16(REG_I2C_DATA_PORT) & 0xff); //copy the read data to the previous transcation owner
341 }
342 handle->transaction_result = I2C_TRANSACTION_COMPLETE;
343 MD_TRC(I2C_TRANSACTION_COMPLETE_MSG,);
344 }
345 else
346 {
347 MD_TRC(I2C_TRANSACTION_ERROR_MSG,sta);
348 if (sta & I2C_TRANSAC_ACK_ERR)
349 handle->transaction_result = I2C_TRANSACTION_ACKERR;
350 else if (sta & I2C_HS_NACK_ERR)
351 handle->transaction_result = I2C_TRANSACTION_HS_NACKERR;
352 else //if got this, check register INTR_STAT to debug
353 handle->transaction_result = I2C_TRANSACTION_FAIL;
354
355 }
356 kal_take_spinlock(i2c_lock_id, KAL_INFINITE_WAIT);
357 dcl_i2c_status.state=I2C_READY_STATE;
358 kal_give_spinlock(i2c_lock_id);
359
360}
361
362
363
364//----------------------------I2C Configuration APIs-------------------------------
365void dcl_i2c_set_transaction_speed(DCL_I2C_OWNER owner,I2C_TRANSACTION_MODE mode,kal_uint16* Fast_Mode_Speed,kal_uint16* HS_Mode_Speed)
366{
367 kal_uint32 step_cnt_div;
368 kal_uint32 sample_cnt_div;
369 kal_uint32 temp;
370
371 //Fast Mode Speed
372 for (sample_cnt_div=1;sample_cnt_div<=8;sample_cnt_div++)
373 {
374 if (NULL != Fast_Mode_Speed)
375 {
376 temp=((*Fast_Mode_Speed)*2*sample_cnt_div);
377 }
378 else
379 {
380 temp = 1*2*sample_cnt_div;
381 }
382 step_cnt_div=(I2C_CLOCK_RATE+temp-1)/temp; //cast the <1 part
383
384 if (step_cnt_div<=64)
385 {
386 break;
387 }
388 }
389 if (step_cnt_div>64 && sample_cnt_div>8)
390 {
391 step_cnt_div=64;
392 sample_cnt_div=8;
393 }
394
395
396
397 if (NULL != Fast_Mode_Speed)
398 {
399 *Fast_Mode_Speed = I2C_CLOCK_RATE/2/sample_cnt_div/step_cnt_div;
400 i2c_handle[owner].fs_sample_cnt_div=sample_cnt_div-1;
401 i2c_handle[owner].fs_step_cnt_div=step_cnt_div-1;
402 i2c_handle[owner].i2c_config.transaction_mode=I2C_TRANSACTION_FAST_MODE;
403
404 }
405
406 //HS Mode Speed
407 if (mode==I2C_TRANSACTION_HIGH_SPEED_MODE)
408 {
409 for (sample_cnt_div=1;sample_cnt_div<=8;sample_cnt_div++)
410 {
411 if (NULL != HS_Mode_Speed)
412 {
413 temp=((*HS_Mode_Speed)*2*sample_cnt_div);
414 }
415 else
416 {
417 temp=(1*2*sample_cnt_div);
418 }
419 step_cnt_div=(I2C_CLOCK_RATE+temp-1)/temp;
420 if (step_cnt_div<=8)
421 {
422 break;
423 }
424 }
425 if (NULL != HS_Mode_Speed)
426 {
427 *HS_Mode_Speed=I2C_CLOCK_RATE/2/sample_cnt_div/step_cnt_div;
428 i2c_handle[owner].hs_sample_cnt_div=sample_cnt_div-1;
429 i2c_handle[owner].hs_step_cnt_div=step_cnt_div-1;
430 i2c_handle[owner].i2c_config.transaction_mode=I2C_TRANSACTION_HIGH_SPEED_MODE;
431 }
432 }
433}
434
435
436#endif
437
438