📄 tmiic.c
字号:
/*
* +-------------------------------------------------------------------+
* | Copyright (c) 1995,1996,1997 by TriMedia Technologies. |
* | |
* | This software is furnished under a license and may only be used |
* | and copied in accordance with the terms and conditions of such a |
* | license and with the inclusion of this copyright notice. This |
* | software or any other copies of this software may not be provided |
* | or otherwise made available to any other person. The ownership |
* | and title of this software is not transferred. |
* | |
* | The information in this software is subject to change without |
* | any prior notice and should not be construed as a commitment by |
* | TriMedia Technologies. |
* | |
* | This code and information is provided "as is" without any |
* | warranty of any kind, either expressed or implied, including but |
* | not limited to the implied warranties of merchantability and/or |
* | fitness for any particular purpose. |
* +-------------------------------------------------------------------+
*
*
* Module name : tmIIC.c 1.68
*
* Last update : 19:33:12 - 00/11/09
*
*
* Description :
*
*
* Revision :
*
*/
/*----------------------------includes----------------------------------------*/
#include <stdio.h>
#include <tm1/tmAssert.h>
#include <tmlib/AppModel.h>
#include <tm1/mmio.h>
#include <tm1/tmIIC.h>
#include <tm1/tmInterrupts.h>
#include <tm1/tmProcessor.h>
#include <tm1/tmIICS.h>
#include <tm1/tmIICmmio.h>
#include <tmlib/dprintf.h> /* for debugging with DP(()) */
#define IIC_DP(x)
/*------------------------- local definitions --------------------------------*/
/* normally, these come from the Makefile */
#ifndef MAJOR_VERSION
#define MAJOR_VERSION 3
#endif
#ifndef MINOR_VERSION
#define MINOR_VERSION 0
#endif
#ifndef BUILD_VERSION
#define BUILD_VERSION 0
#endif
/*
* This macro determines the inclusion of code that detects
* if we're running on a TM1000 so it can wait endlessly
* before/after doing anything
*/
#define TM1000_COMPATIBLE 1
/*
* Default settings for iicReadReg/iicWriteReg
*/
#define MAX_NUM_RETRIES 10
#define TM1100_SLEEP_BEFORE_RETRY 50
/*
* Wait before timeout in case of Synchronous_by_polling
*/
#define MAX_WAIT_IN_US 50000
/*
* Largest number of bytes to transfer in one request
*/
#define LARGEST_TRANSFER 0xfe
/*----------------------------globals---------------------------------------*/
/*
* Keep queue of waiting requests
*/
static piicRequest_t iic_queue_first = Null;
static piicRequest_t iic_queue_last = Null;
/*
* Keep pointer to the transfer currently being executed.
*/
static piicRequest_t iic_current_request;
/*
* Keep some info that is shared over ISRs:
* - Whether we just did a write of a subaddress to do a subaddress read
* - Where we want to read the buffer in case of a subaddress read
* - The number of times we retried this request already.
*/
static Bool SubaddressRead = False;
static UInt32 AddressRegister;
static Int NumRetries = 0;
static volatile UInt LoopCount;
/*
* Default libdev variables
*/
static Int next_instance = 0;
static iicSetup_t IICSetup = {intPRIO_5};
static iicCapabilities_t capabilities =
{
/* version */ {MAJOR_VERSION, MINOR_VERSION, BUILD_VERSION},
/* numSupportedInstances */ -1,
/* numCurrentInstances */ 0,
/* largestTransfer */ LARGEST_TRANSFER
};
/*----------------------------HW-weirdness---------------------------------*/
static pprocCapabilities_t procCap = Null;
static Bool TM1100_1_2;
/*----------------------------TM1000---------------------------------------*/
/*
* Values we only need to workaround tm1000 hw bugs
*/
#if TM1000_COMPATIBLE
#define TM1000_SLEEP_BEFORE_WRITE 600 /* workaround for hw bugsw */
static Bool TM1000;
#endif
/*----------------------------TM2000---------------------------------------*/
void* _iicsISR = Null;
UInt32 _iicsMask = 0;
/*----------------------------macros---------------------------------------*/
/*
* Copy max 4 bytes into the data field of request r
*/
#define COPY_IN(r, d) { \
int i; \
for (i = 3; i >= 0 && (r)->index < (r)->byteCount; \
i--, (r)->index++) \
(r)->data[(r)->index] = ((d)>>i*8) & 0xff ; \
}
/*
* Copy max 4 bytes out of the data field of request r into d
*/
#define COPY_OUT(r, d) \
*(d) = (r)->data[(r)->index ]<<24 | \
(r)->data[(r)->index+1]<<16 | \
(r)->data[(r)->index+2]<<8 | \
(r)->data[(r)->index+3] ; \
(r)->index += 4;
/*
* Copy max 4 bytes out of the data field of request r into d
* If sub then make sure the lm byte is the subaddress.
*/
#define COPY_OUT_SUB(r, d, sub) \
if (sub) { \
*(d) = (r)->subaddress <<24 | \
(r)->data[(r)->index ]<<16 | \
(r)->data[(r)->index+1]<<8 | \
(r)->data[(r)->index+2] ; \
(r)->index += 3; \
} else { \
COPY_OUT((r), (d)); \
}
/*----------------------------local-functions---------------------------------*/
static void
start_next_transfer(Bool retry)
{
UInt32 data;
UInt8 byteCount = iic_current_request->byteCount;
Bool subaddress_write = False;
UInt8 address = iic_current_request->address;
IIC_DP(("start_next_transfer, %x\n", iic_current_request));
if (!retry) {
NumRetries = 0;
} else {
intSET_IEN();
microsleep(iic_current_request->waitBeforeRetry);
intCLEAR_IEN();
}
if (iic_current_request->type == IIC_SUBADDRESS || iic_current_request->direction == IIC_WRITE) {
#if TM1000_COMPATIBLE
if (TM1000) {
intSET_IEN();
microsleep(TM1000_SLEEP_BEFORE_WRITE);
intCLEAR_IEN();
}
#endif
}
LoopCount = 0;
if (iic_current_request->type == IIC_SUBADDRESS) {
if (iic_current_request->direction == IIC_READ) {
/*
* In case of a subaddress read, write the sub address and
* flag the fact that you need to read in the ISR
*/
SubaddressRead = True;
AddressRegister = (iic_current_request->address << 24) | (byteCount << 8);
MMIO(IIC_CTL) = IIC_CLR_ALL | IIC_GD_IEN | IIC_FIEN |
IIC_ANIEN | IIC_DNIEN | IIC_ENABLE;
MMIO(IIC_AR) = ((address & 0xFE) << 24) | (1 << 8);
MMIO(IIC_DR) = iic_current_request->subaddress << 24;
return;
} else {
/*
* In case of a subaddress write, write one extra byte
* holding the subaddress
*/
subaddress_write = True;
byteCount++;
}
}
#if TM1000_COMPATIBLE
if (TM1000 && iic_current_request->direction == IIC_WRITE) {
byteCount++; /* workaround HW bug */
}
#endif
MMIO(IIC_CTL) = IIC_CLR_ALL | IIC_GD_IEN | IIC_FIEN |
IIC_ANIEN | IIC_DNIEN | IIC_ENABLE;
MMIO(IIC_AR) = (address << 24) | (byteCount << 8);
if (iic_current_request->direction == IIC_WRITE) {
COPY_OUT_SUB(iic_current_request, &data, subaddress_write);
MMIO(IIC_DR) = data;
}
}
static void
_iic_handler(void)
{
UInt32 data, status, acker=0;
status = MMIO(IIC_STATUS);
/*
* Check the four bits in the status register that need
* to be cleared. Clearing is done 6 bits to the right,
* in the control register. See Databook Figure 15-2.
*/
acker = (status & 0xf0000000) >> 6;
MMIO(IIC_CTL) |= acker;
/*
* If we are running on a TM2 we have to check for
* IICS interrupts as well, and call the iicsISR if
* needed.
*/
if ((status & _iicsMask) && (_iicsISR != Null)) {
((iicsFunc_t)_iicsISR)(status);
}
/*
* On an error interrupt, retry, or fall thru, so that
* the done flag is set and the requester is resumed.
*/
if (iicANACK(status) || iicDNACK(status)) {
if (++NumRetries <= iic_current_request->numRetries) {
iic_current_request->index = 0;
start_next_transfer(True); /* starts iic_current_request, retry */
return;
}
if (iicANACK(status)) {
iic_current_request->errorCode |= IIC_ERR_ADDRESS_NACK;
} else {
iic_current_request->errorCode |= IIC_ERR_DATA_NACK;
}
}
/*
* When we get an FI, we have to read the data from or put new
* data into the data register.
* If we just wrote a Subaddress to a slave, we know we will not
* do anything.
*/
if (iicFI(status) || iicGDI(status) ) {
if (!SubaddressRead) {
if (iic_current_request->direction == IIC_READ) {
data = MMIO(IIC_DR);
COPY_IN(iic_current_request, data);
} else if (iic_current_request->byteCount + (iic_current_request->type==IIC_SUBADDRESS?1:0) > iic_current_request->index) {
COPY_OUT(iic_current_request, &data);
MMIO(IIC_DR) = data;
}
}
}
/*
* On a GDI we know we are done
*/
if (iicGDI(status) || iicANACK(status) || iicDNACK(status)) {
piicRequest_t current = iic_current_request;
if (iicGDI(status)) {
if (SubaddressRead) {
SubaddressRead = False;
/*
* Start up the read of the subaddress now the
* the subaddress is written to the slave.
*/
MMIO(IIC_CTL) = IIC_CLR_ALL | IIC_GD_IEN | IIC_FIEN |
IIC_ANIEN | IIC_DNIEN | IIC_ENABLE;
MMIO(IIC_AR) = AddressRegister;
return;
}
}
/*
* Done with current transaction, or current transaction failed:
* - set done flag, to wake up polling tasks
* - start a next transaction, if any
* - resume synchronous waiting tasks
* - call completion function
*/
iic_current_request = iic_queue_first;
current->done = True;
IIC_DP(("Completed iic %x\n", current));
if (iic_current_request != Null)
{
iic_queue_first = iic_queue_first->link;
if (iic_queue_first == Null) {
iic_queue_last = Null;
}
start_next_transfer(False); /* starts iic_current_request, no retries */
}
if (current->mode == IIC_Synchronous) {
AppModel_resume(current->requester);
}
if (current->completion_function) {
IIC_DP(("Completion func of %x\n", current));
current->completion_function(current);
}
}
}
static void iic_handler(void)
{
#pragma TCS_handler
AppModel_suspend_scheduling();
AppModel_run_on_sstack((AppModel_Fun)_iic_handler, Null);
AppModel_resume_scheduling();
}
/*----------------------------functions---------------------------------------*/
extern tmLibdevErr_t
iicWriteReg(UInt address, Int subaddress, UInt value)
{
Int instance = 0;
iicRequest_t req;
tmLibdevErr_t err;
UInt8 data = value;
if (err = iicOpen(&instance))
return err;
req.direction = IIC_WRITE;
req.byteCount = 1;
req.address = address;
req.subaddress = subaddress;
req.numRetries = MAX_NUM_RETRIES;
req.waitBeforeRetry = TM1100_SLEEP_BEFORE_RETRY;
req.data = &data;
req.mode = IIC_Synchronous_By_Polling;
req.type = (subaddress < 0) ? IIC_SIMPLE : IIC_SUBADDRESS;
req.completion_function = Null;
err = iicDispatch(instance, &req);
err |= iicClose(instance);
return err;
}
extern tmLibdevErr_t
iicReadReg(UInt address, Int subaddress, UInt * value)
{
Int instance = 0;
iicRequest_t req;
tmLibdevErr_t err;
UInt8 data;
if (err = iicOpen(&instance))
return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -