250 lines
6.2 KiB
C
250 lines
6.2 KiB
C
|
/*****************************************************************************
|
||
|
Copyright(c) 2014 FCI Inc. All Rights Reserved
|
||
|
|
||
|
File name : fci_i2c.c
|
||
|
|
||
|
Description : source of internal i2c driver
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
||
|
History :
|
||
|
----------------------------------------------------------------------
|
||
|
*******************************************************************************/
|
||
|
#include "fci_types.h"
|
||
|
#include "fci_oal.h"
|
||
|
#include "fc8180_regs.h"
|
||
|
#include "fci_hal.h"
|
||
|
|
||
|
#define I2CSTAT_TIP 0x02 /* Tip bit */
|
||
|
#define I2CSTAT_NACK 0x80 /* Nack bit */
|
||
|
|
||
|
#define I2C_TIMEOUT 100
|
||
|
|
||
|
#define I2C_CR_STA 0x80
|
||
|
#define I2C_CR_STO 0x40
|
||
|
#define I2C_CR_RD 0x20
|
||
|
#define I2C_CR_WR 0x10
|
||
|
#define I2C_CR_NACK 0x08
|
||
|
#define I2C_CR_IACK 0x01
|
||
|
|
||
|
#define I2C_WRITE 0
|
||
|
#define I2C_READ 1
|
||
|
|
||
|
#define I2C_OK 0
|
||
|
#define I2C_NOK 1
|
||
|
#define I2C_NACK 2
|
||
|
#define I2C_NOK_LA 3 /* Lost arbitration */
|
||
|
#define I2C_NOK_TOUT 4 /* time out */
|
||
|
|
||
|
#define FC8180_FREQ_XTAL BBM_XTAL_FREQ
|
||
|
|
||
|
/*static OAL_SEMAPHORE hBbmMutex;*/
|
||
|
|
||
|
static s32 WaitForXfer(HANDLE handle)
|
||
|
{
|
||
|
s32 i;
|
||
|
s32 res = I2C_OK;
|
||
|
u8 status;
|
||
|
|
||
|
i = I2C_TIMEOUT * 20000;
|
||
|
/* wait for transfer complete */
|
||
|
do {
|
||
|
bbm_read(handle, BBM_I2C_SR, &status);
|
||
|
i--;
|
||
|
} while ((i > 0) && (status & I2CSTAT_TIP));
|
||
|
|
||
|
/* check time out or nack */
|
||
|
if (status & I2CSTAT_TIP) {
|
||
|
res = I2C_NOK_TOUT;
|
||
|
} else {
|
||
|
bbm_read(handle, BBM_I2C_SR, &status);
|
||
|
if (status & I2CSTAT_NACK)
|
||
|
res = I2C_NACK;
|
||
|
else
|
||
|
res = I2C_OK;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static s32 fci_i2c_transfer(HANDLE handle, u8 cmd_type, u8 chip, u8 addr[],
|
||
|
u8 addr_len, u8 data[], u8 data_len)
|
||
|
{
|
||
|
s32 i;
|
||
|
s32 result = I2C_OK;
|
||
|
|
||
|
switch (cmd_type) {
|
||
|
case I2C_WRITE:
|
||
|
bbm_write(handle, BBM_I2C_TXR, chip | cmd_type);
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_STA | I2C_CR_WR /*0x90*/);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
|
||
|
if (addr && addr_len) {
|
||
|
i = 0;
|
||
|
while ((i < addr_len) && (result == I2C_OK)) {
|
||
|
bbm_write(handle, BBM_I2C_TXR, addr[i]);
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_WR);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i = 0;
|
||
|
while ((i < data_len) && (result == I2C_OK)) {
|
||
|
bbm_write(handle, BBM_I2C_TXR, data[i]);
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_WR /*0x10*/);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_STO /*0x40*/);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
break;
|
||
|
case I2C_READ:
|
||
|
if (addr && addr_len) {
|
||
|
bbm_write(handle, BBM_I2C_TXR, chip | I2C_WRITE);
|
||
|
/* send start */
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_STA | I2C_CR_WR);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
|
||
|
i = 0;
|
||
|
while ((i < addr_len) && (result == I2C_OK)) {
|
||
|
bbm_write(handle, BBM_I2C_TXR, addr[i]);
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_WR);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bbm_write(handle, BBM_I2C_TXR, chip | I2C_READ);
|
||
|
/* resend start */
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_STA | I2C_CR_WR);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK)
|
||
|
return result;
|
||
|
|
||
|
i = 0;
|
||
|
while ((i < data_len) && (result == I2C_OK)) {
|
||
|
if (i == data_len - 1) {
|
||
|
/* No Ack Read */
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_RD |
|
||
|
I2C_CR_NACK);
|
||
|
result = WaitForXfer(handle);
|
||
|
if ((result != I2C_NACK) && (result !=
|
||
|
I2C_OK)) {
|
||
|
print_log(handle, "NACK4-0[%02x]\n",
|
||
|
result);
|
||
|
return result;
|
||
|
}
|
||
|
} else {
|
||
|
/* Ack Read */
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_RD);
|
||
|
result = WaitForXfer(handle);
|
||
|
if (result != I2C_OK) {
|
||
|
print_log(handle, "NACK4-1[%02x]\n",
|
||
|
result);
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
bbm_read(handle, BBM_I2C_RXR, &data[i]);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
/* send stop */
|
||
|
bbm_write(handle, BBM_I2C_CR, I2C_CR_STO /*0x40*/);
|
||
|
result = WaitForXfer(handle);
|
||
|
if ((result != I2C_NACK) && (result != I2C_OK)) {
|
||
|
print_log(handle, "NACK5[%02X]\n", result);
|
||
|
return result;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return I2C_NOK;
|
||
|
}
|
||
|
|
||
|
return I2C_OK;
|
||
|
}
|
||
|
|
||
|
s32 fci_i2c_init(HANDLE handle, s32 speed, s32 slaveaddr)
|
||
|
{
|
||
|
u16 r = FC8180_FREQ_XTAL % (5 * speed);
|
||
|
u16 pr = (FC8180_FREQ_XTAL - r) / (5 * speed) - 1;
|
||
|
|
||
|
if (((5 * speed) >> 1) <= r)
|
||
|
pr++;
|
||
|
|
||
|
/*OAL_CREATE_SEMAPHORE(&hBbmMutex, "int_i2c", 1, OAL_FIFO);*/
|
||
|
|
||
|
bbm_word_write(handle, BBM_I2C_PR_L, pr);
|
||
|
bbm_write(handle, BBM_I2C_CTR, 0xc0);
|
||
|
|
||
|
print_log(handle, "Internal I2C Pre-scale: 0x%02x\n", pr);
|
||
|
|
||
|
return BBM_OK;
|
||
|
}
|
||
|
|
||
|
s32 fci_i2c_read(HANDLE handle, u8 chip, u8 addr, u8 alen, u8 *data, u8 len)
|
||
|
{
|
||
|
s32 ret;
|
||
|
|
||
|
/*OAL_OBTAIN_SEMAPHORE(&hBbmMutex, OAL_SUSPEND);*/
|
||
|
ret = fci_i2c_transfer(handle, I2C_READ, chip << 1, &addr, alen, data,
|
||
|
len);
|
||
|
/*OAL_RELEASE_SEMAPHORE(&hBbmMutex);*/
|
||
|
|
||
|
if (ret != I2C_OK) {
|
||
|
print_log(handle, "fci_i2c_read() result=%d, addr = %x, data=%x\n", ret, addr, *data);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
s32 fci_i2c_write(HANDLE handle, u8 chip, u8 addr, u8 alen, u8 *data, u8 len)
|
||
|
{
|
||
|
s32 ret;
|
||
|
u8 *paddr = &addr;
|
||
|
|
||
|
/*OAL_OBTAIN_SEMAPHORE(&hBbmMutex, OAL_SUSPEND);*/
|
||
|
ret = fci_i2c_transfer(handle, I2C_WRITE, chip << 1, paddr, alen, data,
|
||
|
len);
|
||
|
/*OAL_RELEASE_SEMAPHORE(&hBbmMutex);*/
|
||
|
|
||
|
if (ret != I2C_OK)
|
||
|
print_log(handle, "fci_i2c_write() result=%d, addr= %x, data=%x\n", ret, addr, *data);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
s32 fci_i2c_deinit(HANDLE handle)
|
||
|
{
|
||
|
bbm_write(handle, BBM_I2C_CTR, 0x00);
|
||
|
/*OAL_DELETE_SEMAPHORE(&hBbmMutex);*/
|
||
|
return BBM_OK;
|
||
|
}
|
||
|
|