⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xsli2c.c

📁 X-scale 27x 平台
💻 C
字号:
//
// Copyright (c) Chrontel Inc.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Chrontel end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  
  XslI2C.c

Abstract:  
   Read/Write I2C registers using Xscale I2C unit.

Revision:
   11/27/02 Created by Roger Yu, 
      Following PXA250 DM section 9.6.2, 9.6.3

Notes: 
--*/

#include "chrontel.h"

//extern REG_MAP  Xsl_MapReg[REGCAT_SIZE];

/*  /@@@Defined in xslreg.h
//
// I2C
//
typedef struct
{
    unsigned long    ibmr;       //I2C bus monitor register
    unsigned long rsvd0;
    unsigned long    idbr;       //I2C data buffer register
    unsigned long rsvd1;
    unsigned long    icr;        //I2C control register
    unsigned long rsvd2;
    unsigned long    isr;        //I2C status register
    unsigned long rsvd3;
    unsigned long    isar;       //I2C slave address register
    unsigned long rsvd4;
    unsigned long    i2ccr;      //I2C clock count register
} I2C_REGS, *PI2C_REGS;
*/

// ICR initialization value
#define I2C_ICR_INIT (I2C_ICR_BEIE | I2C_ICR_IRFIE | I2C_ICR_ITEIE | I2C_ICR_GCD | I2C_ICR_SCLE)
#define I2C_ISR_INIT 0x7ff
// set slave address for device as 0x00
#define I2C_ISAR_INIT  0x00	                  

#define I2C_TIMEOUT 3

static	volatile I2C_REGS* iic;
static  int pxa_i2c_error_status=0;


static __inline void i2c_Start()
{
	iic->icr |= I2C_ICR_START;
	iic->icr &= ~(I2C_ICR_STOP | I2C_ICR_ALDIE | I2C_ICR_ACKNAK);
}

static __inline void i2c_Restart()
{
	iic->icr |= I2C_ICR_START;
	iic->icr &= ~(I2C_ICR_STOP | I2C_ICR_ALDIE );
}

static __inline void i2c_Stop(int ack)
{
	iic->icr |= I2C_ICR_STOP;
	if (ack) iic->icr |= I2C_ICR_ACKNAK; else iic->icr &= ~I2C_ICR_ACKNAK;
	iic->icr &= ~(I2C_ICR_START);
}

static __inline void i2c_Middle()
{
	iic->icr &= ~(I2C_ICR_START | I2C_ICR_STOP);
}

static __inline void i2c_Abort()
{
	iic->icr |= I2C_ICR_MA;
}


static __inline void i2c_SetData(unsigned data)
{
	iic->idbr = data;
}


static __inline unsigned i2c_GetData()
{
	return (iic->idbr);
}

static __inline int i2c_WaitNoBusy()
{
	int to = I2C_TIMEOUT;
	while (to-- && (I2C_ISR_IBB & iic->isr)) delay_us(100);
	return (to<=0);  // return 0 for success
}


static __inline int i2c_WaitITE()
{
	int to = I2C_TIMEOUT;
	ULONG status;

	while (to--) {
		status = iic->isr;
	    if (I2C_ISR_BED & status) return -2;   // buserror
		if (I2C_ISR_ITE & status) {
		    iic->isr |= I2C_ISR_ITE;   // clear ITE
			return 0;
		}
		delay_us(100);
	}
	return (-1);  // return 0 for success
}


static __inline int i2c_WaitIRF()
{
	int to = I2C_TIMEOUT;
	ULONG status;

	while (to--) {
		status = iic->isr;
	    if (I2C_ISR_BED & status) return -2;   // buserror
		if (I2C_ISR_IRF & status) {
		    iic->isr |= I2C_ISR_IRF;   // clear IRF
			return 0;
		}
		delay_us(100);
	}
	return (-1);  // return 0 for success
}


static __inline void i2c_Reset()
{
	iic->icr &= ~(I2C_ICR_IUE);  // disable unit
	iic->icr |= (I2C_ICR_UR);    // reset unit
	delay_us(100);
	iic->icr &= ~(I2C_ICR_IUE);  // disable unit

	iic->isar = I2C_ISAR_INIT;   // set my slave address
	iic->icr = I2C_ICR_INIT;     // 
	iic->isr = I2C_ISR_INIT;
 
	iic->icr |= (I2C_ICR_IUE);  // enable unit

	delay_us(500);
}


int I2CError()
{
	return pxa_i2c_error_status;
}

void I2CInitialize()
{
	iic = (volatile I2C_REGS*)Xsl_MapReg[I2CREG].mapaddr;
    i2c_Reset();  
	
	delay_us(5000);
}


/*
>>>>> Write 1 Byte as a Master <<<<<
1. Load target slave address and R/nW bit in the IDBR. R/nW must be 0 for a write.
2. Initiate the write.
Set ICR[START], clear ICR[STOP], clear ICR[ALDIE], set ICR[TB]
3. When an IDBR Transmit Empty interrupt occurs.
Read ISR: IDBR Transmit Empty (1), Unit Busy (1), R/nW bit (0)
4. Write a 1 to the ISR[ITE] bit to clear interrupt.
5. Write a 1 to the ISR[ALD] bit if set.
If the master loses arbitration, it performs an address retry when the bus becomes free. The
Arbitration Loss Detected interrupt is disabled to allow the address retry.
6. Load data byte to be transferred in the IDBR.
7. Initiate the write.
Clear ICR[START], set ICR[STOP], set ICR[ALDIE], set ICR[TB]
8. When an IDBR Transmit Empty interrupt occurs (unit is sending STOP).
Read ISR: IDBR Transmit Empty (1), Unit busy (x), R/nW bit (0)
9. Write a 1 to the ISR[ITE] bit to clear the interrupt.
10. Clear ICR[STOP] bit.
*/

void I2CWriteReg( unsigned addr, unsigned index, unsigned value)
{
	int error;
	
	iic = (volatile I2C_REGS*)Xsl_MapReg[I2CREG].mapaddr;
	// assume no I2C error
	pxa_i2c_error_status =0;

	error=i2c_WaitNoBusy();
	if (error) goto i2cerr;    // exit if i2c always busy


//$$$ Address
//1	
	iic->idbr = (addr & 0xfe);   // 8-bit slave address with R/w=0
//2
	iic->icr |= I2C_ICR_START;
//	iic->icr &= ~(I2C_ICR_STOP | I2C_ICR_ALDIE | I2C_ICR_ACKNAK);
	iic->icr &= ~(I2C_ICR_STOP | I2C_ICR_ALDIE);

	iic->icr |= I2C_ICR_TB;
//3,4
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;
//5
	if ((I2C_ISR_ALD) & iic->isr)  iic->isr |= I2C_ISR_ALD;  // clear ALD
//$$$ Index
//6
	iic->idbr = (index & 0xff);
//7a  //Since we need send total 3bytes out, here step 7 is different
	iic->icr &= ~(I2C_ICR_START | I2C_ICR_STOP);
    iic->icr |= I2C_ICR_ALDIE;

	iic->icr |= I2C_ICR_TB;
//8,9
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;

//$$$ Value
//6
	iic->idbr = value;
//7a  //Since we need send total 3bytes out, here step 7 is different
	iic->icr &= ~(I2C_ICR_START );
	iic->icr |= (I2C_ICR_STOP | I2C_ICR_ALDIE);

	iic->icr |= I2C_ICR_TB;
//8,9
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;
//10
	iic->icr &= ~(I2C_ICR_STOP | I2C_ICR_ALDIE);

	return;

i2cerr:
	pxa_i2c_error_status = error;

    i2c_Reset();

	return;
}


/*
>>>>> Read 1 Byte as a Master  <<<<<
1. Load target slave address and R/nW bit in the IDBR. R/nW must be 1 for a read.
2. Initiate the write.
Set ICR[START], clear ICR[STOP], clear ICR[ALDIE], set ICR[TB]
3. When an IDBR Transmit Empty interrupt occurs.
Read ISR: IDBR Transmit Empty (1), Unit busy (1), R/nW bit (1)
4. Write a 1 to the ISR[ITE] bit to clear the interrupt.
5. Initiate the read.
Clear ICR[START], set ICR[STOP], set ICR[ALDIE], set ICR[ACKNAK], set ICR[TB]
6. When an IDBR Receive full interrupt occurs (unit is sending STOP).
Read ISR: IDBR Receive Full (1), Unit Busy (x), R/nW bit (1), ACK/NAK bit (1)
7. Write a 1 to the ISR[IRF] bit to clear the interrupt.
8. Read IDBR data.
9. Clear ICR[STOP] and ICR[ACKNAK] bits


*/

unsigned I2CReadReg( unsigned addr, unsigned index)
{
	ULONG value;
	int error;

    iic = (volatile I2C_REGS*)Xsl_MapReg[I2CREG].mapaddr;

// assume no i2c error first.
    pxa_i2c_error_status =0;

	error=i2c_WaitNoBusy();
	if (error) goto i2cerr;    // exit if i2c always busy

//$$$ Slave address
//1	
	iic->idbr = (addr & 0xfe);   // 8-bit slave address with R/w=0
//2
	iic->icr |= I2C_ICR_START;
	iic->icr &= ~( I2C_ICR_STOP | I2C_ICR_ALDIE | I2C_ICR_ACKNAK);

	iic->icr |= I2C_ICR_TB;   // transfer

//3,4
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;
//5
	if (I2C_ISR_ALD & iic->isr)  iic->isr |= I2C_ISR_ALD;  // clear ALD

//$$$ Index
//6
	iic->idbr = (index & 0xff);
//7b  //Since we need send total 2bytes with RESTART, here step 7 no STOP
	iic->icr &= ~(I2C_ICR_START | I2C_ICR_STOP);
    iic->icr |= I2C_ICR_ALDIE;

	iic->icr |= I2C_ICR_TB;
//8,9
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;
//$$$ Restart for read
//1	
	iic->idbr = (addr | 0x01);   // 8-bit slave address with R/w=1
//2
	iic->icr |= I2C_ICR_START;
	iic->icr &= ~( I2C_ICR_STOP | I2C_ICR_ALDIE);

	iic->icr |= I2C_ICR_TB;   // transfer

//3,4
	error = i2c_WaitITE();   // wait Transmit Empty,  and clear ITE if set
	if (error) goto i2cerr;
//5
	iic->icr &= ~I2C_ICR_START;
	iic->icr |= (I2C_ICR_STOP | I2C_ICR_ALDIE | I2C_ICR_ACKNAK);

	iic->icr |= I2C_ICR_TB;
//6,7
	error = i2c_WaitIRF();    // wait Receive Buffer Full
	if (error) goto i2cerr;
//8
	value = iic->idbr;
//9
	iic->icr &= ~( I2C_ICR_STOP | I2C_ICR_ACKNAK | I2C_ICR_ALDIE); 

	return (0xFF & value);

i2cerr:
	pxa_i2c_error_status = error;

    i2c_Reset();

	return  (ULONG)-1;
}



void I2CWriteRegBits(  unsigned addr, unsigned index, unsigned mask, unsigned value)
{
    unsigned val;

	val = I2CReadReg(addr, index);
	val &= ~mask;
	val |= value;
	I2CWriteReg( addr, index, val);
	return;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -