/*******************************************************************************
*
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2007 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
*
********************************************************************************
*
* File Name:  can.c
*
* $Date:      Oct-12-2010$
*
* $Version:   2.3.6.0$
*
* Description: Source file for the msCAN driver
*
*****************************************************************************/

#include "qs.h"
#include "mscan.h"

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************
 canInit() function performs the CAN module static configuration
 based on the configurable items from appconfig.h 
********************************************************************************/

void mscanInit(arch_sMSCAN *pCanBase)
{
	/* enter soft-reset state */
	ioctl(pCanBase, MSCAN_SOFT_RESET, MSCAN_ON);

	/* initialize control registers writable in reset-state only */
	#ifdef MSCAN_CANIDAC_INIT
	periphMemWrite(MSCAN_CANIDAC_INIT, &pCanBase->canidac);
	#endif

	#ifdef MSCAN_CANIDAR0_INIT
	periphMemWrite(MSCAN_CANIDAR0_INIT, &pCanBase->canidar0);
	#endif
	#ifdef MSCAN_CANIDAR1_INIT
	periphMemWrite(MSCAN_CANIDAR1_INIT, &pCanBase->canidar1);
	#endif
	#ifdef MSCAN_CANIDAR2_INIT
	periphMemWrite(MSCAN_CANIDAR2_INIT, &pCanBase->canidar2);
	#endif
	#ifdef MSCAN_CANIDAR3_INIT
	periphMemWrite(MSCAN_CANIDAR3_INIT, &pCanBase->canidar3);
	#endif
	#ifdef MSCAN_CANIDAR4_INIT
	periphMemWrite(MSCAN_CANIDAR4_INIT, &pCanBase->canidar4);
	#endif
	#ifdef MSCAN_CANIDAR5_INIT
	periphMemWrite(MSCAN_CANIDAR5_INIT, &pCanBase->canidar5);
	#endif
	#ifdef MSCAN_CANIDAR6_INIT
	periphMemWrite(MSCAN_CANIDAR6_INIT, &pCanBase->canidar6);
	#endif
	#ifdef MSCAN_CANIDAR7_INIT
	periphMemWrite(MSCAN_CANIDAR7_INIT, &pCanBase->canidar7);
	#endif
	
	#ifdef MSCAN_CANIDMR0_INIT
	periphMemWrite(MSCAN_CANIDMR0_INIT, &pCanBase->canidmr0);
	#endif
	#ifdef MSCAN_CANIDMR1_INIT
	periphMemWrite(MSCAN_CANIDMR1_INIT, &pCanBase->canidmr1);
	#endif
	#ifdef MSCAN_CANIDMR2_INIT
	periphMemWrite(MSCAN_CANIDMR2_INIT, &pCanBase->canidmr2);
	#endif
	#ifdef MSCAN_CANIDMR3_INIT
	periphMemWrite(MSCAN_CANIDMR3_INIT, &pCanBase->canidmr3);
	#endif
	#ifdef MSCAN_CANIDMR4_INIT
	periphMemWrite(MSCAN_CANIDMR4_INIT, &pCanBase->canidmr4);
	#endif
	#ifdef MSCAN_CANIDMR5_INIT
	periphMemWrite(MSCAN_CANIDMR5_INIT, &pCanBase->canidmr5);
	#endif
	#ifdef MSCAN_CANIDMR6_INIT
	periphMemWrite(MSCAN_CANIDMR6_INIT, &pCanBase->canidmr6);
	#endif
	#ifdef MSCAN_CANIDMR7_INIT
	periphMemWrite(MSCAN_CANIDMR7_INIT, &pCanBase->canidmr7);
	#endif

	#ifdef MSCAN_CANBTR0_INIT
	periphMemWrite(MSCAN_CANBTR0_INIT, &pCanBase->canbtr0);
	#endif
	
	#ifdef MSCAN_CANBTR1_INIT
	periphMemWrite(MSCAN_CANBTR1_INIT, &pCanBase->canbtr1);
	#endif

	#ifdef MSCAN_CANCTL1_INIT
	periphMemWrite(MSCAN_CANCTL1_INIT, &pCanBase->canctl1);
	#endif
	
	/* initialize the rest of main control register */
	#ifdef MSCAN_CANCTL0_INIT
	periphMemWrite(MSCAN_CANCTL0_INIT, &pCanBase->canctl0);
	#if !((MSCAN_CANCTL0_INIT) & (MSCAN_CANCTL0_INITRQ))
    	/* redo to update the register bits again after SOFT_RESET state is left */
    	periphMemWrite(MSCAN_CANCTL0_INIT, &pCanBase->canctl0);
	#endif
	#endif
	
	#ifdef MSCAN_CANRIER_INIT
	periphMemWrite(MSCAN_CANRIER_INIT, &pCanBase->canrier);
	#endif

	#ifdef MSCAN_CANTCR_INIT
	periphMemWrite(MSCAN_CANTCR_INIT, &pCanBase->cantcr);
	#endif

}

/* ID->RAW calculation implemented as inline assembly */

inline UWord32 MSCAN_Id2Idr_IASM(register UWord32 id)
{
	register UWord32 ret;
	
	asm {
		tfr id,A;
	
		/* id is in A register */
		brclr #0x8000, A1, std_id;
	
	ext_id:
		asll.l #1,A;		/* move bits IDR[17-0] to right position (A0 is okay) */
		move.w A1,Y1;		/* save upper half of IDR */
		
		bfclr #0xfff8,A1;	/* leave only IDR[17-15] in A1 */
		bfclr #0x7,Y1;		/* leave only IDR[28-18] in Y1 */
		asll.w #2,Y1;		/* move IDR[28-18] to right position */
		or.w Y1,A;			/* build complete IDR in A */
		bfset #0x18,A1;		/* set SRR and IDE bit */
		bra <rtrn;
	
	std_id:
		asll.l #21,A;

	rtrn:
		tfr A,ret;
	}

	/* return in A	*/
	return ret;
}

/* RAW->ID calculation implemented as inline assembly */

inline UWord32 MSCAN_Idr2Id_IASM(register UWord32 idr)
{
	register UWord32 ret;

	asm {
		tfr idr, A;
		
		/* decide the ID type */
		brclr #8, A1, std_id;		/* jump to process std ID */

	ext_id:
		lsrr.l #1, A;				/* move bits ID[17-0] to the right place */
		tfr A,B;					/* save bits ID[17-0] */
		bfclr #0xfffc,B1;			/* leave only ID[17-0] saved */
		
		lsrr.w #2,A;				/* move bits ID[28-18] to the right place (zero A0) */
		bfclr #0x3,A1;				/* zero position on ID[17-16] */
		or.l B,A;
		bfset #0x8000,A1;			/* mark extended ID (bit 31) */
		bra <rtrn;
		
	std_id:
		lsrr.l #21, A;
	
	rtrn:
		tfr A,ret;
	}

	/* return in A	*/
	return ret;
}


/* ID->RAW calculation implemented as a function call */

#pragma interrupt called
UWord32 MSCAN_Id2Idr_V(register UWord32 id)
{
	return MSCAN_Id2Idr_IASM(id);
}

/* RAW->ID calculation implemented as a function call */

#pragma interrupt called
UWord32 MSCAN_Idr2Id_V(register UWord32 idr)
{
	return MSCAN_Idr2Id_IASM(idr);
}

/* same as MSCANMB_SET_ID but implemented as function (to be used when ID passed is a variable) */

#pragma interrupt called
void ioctlMSCANMB_SET_ID_V(register arch_sMSCAN_MB* pMSCanMB, register UWord32 id)
{
	register UWord32 idr = MSCAN_Id2Idr_IASM(id);
	
	/* set RTR ? */
	if(id & MSCAN_ID_RTR)
		idr |= MSCAN_MB_IDR3_ERTR | (((UWord32)MSCAN_MB_IDR1_SRTR) << 16);
				
	ioctl(pMSCanMB, MSCANMB_SET_ID_RAW, idr);
}

/* Retrieve 32bit ID from the apropriate bits in given MB */

#pragma interrupt called
UWord32 ioctlMSCANMB_GET_ID(register arch_sMSCAN_MB* pMSCanMB, void*)
{
	register UWord16* pidr = (UWord16*) &pMSCanMB->idr0;
	register UWord32 ret;

	asm { 
		/* retrieve IDR as 32bit number into A (see also MSCANMB_GET_ID_RAW) */
		move.w X:(pidr+0),A1;
		move.w X:(pidr+2),A0;
		asll.l #8,A;
		move.w X:(pidr+1),B1;
		move.w X:(pidr+3),B0;
		or.l B,A;

		/* decide the ID type */
		brclr #8, A1, std_id;		/* jump to process std ID */

	ext_id:
		lsrr.l #1, A;				/* move bits ID[17-0] to the right place */
		tfr A,B;					/* save bits ID[17-0] */
		bfclr #0xfffc,B1;			/* leave only ID[17-0] saved */
		
		lsrr.w #2,A;				/* move bits ID[28-18] to the right place (zero A0) */
		bfclr #0x3,A1;				/* zero position on ID[17-16] */
		or.l B,A;
		bfset #0x8000,A1;			/* mark extended ID (bit 31) */
		bra <rtrn;
		
	std_id:
		lsrr.l #21, A;
	
	rtrn:
		tfr A,ret;
	}
	
	return ret;	
}

 
#ifdef __cplusplus
}
#endif

