NvBool NvOdmEcompassOpen(NvOdmEcompassHandle* hDevice)
{
	NvU32 i;
	NvOdmEcompassHandle	hEcompass;
	NvOdmIoModule IoModule = NvOdmIoModule_I2c;
	const NvOdmPeripheralConnectivity *pConnectivity;
	NvBool FoundGpio = NV_FALSE, FoundI2cModule = NV_FALSE;

	hEcompass = NvOdmOsAlloc(sizeof(NvOdmEcompass));
	if (hEcompass == NULL)
	{
		NVODMECOMPASS_PRINTF(("AKM8975 compass driver: Open fail\n"));
		return NV_FALSE;
	}
	NvOdmOsMemset(hEcompass,0,sizeof(NvOdmEcompass));
	hEcompass->nBusType = NV_ECOMPASS_BUS_I2C;
	
	// Info of ecompass with current setting
	
    pConnectivity = (NvOdmPeripheralConnectivity*)NvOdmPeripheralGetGuid(
                        ECOMPASS_GUID);
    if (!pConnectivity)
    {
        NvOdmOsDebugPrintf(("NvOdmPeripheralGetGuid doesn't detect\
           AKM8975/B device\n"));
        goto error;
    }
static NvBool
WriteReg(
    NvOdmEcompassHandle hDevice,
    NvU8 RegAddr,
    NvU8* value,
    NvU32 len)
{
    NvOdmI2cTransactionInfo TransactionInfo;

    if ( (NULL == hDevice) || (NULL == value) ||
         (len > I2C_ECOMPASS_PACKET_SIZE-1 ) )
    {
        NVODMECOMPASS_PRINTF(("NvOdmI2c Set Regs Failed, max size is %d bytes\n", I2C_ECOMPASS_PACKET_SIZE-1));
        return NV_FALSE;
    }

    s_WriteBuffer[0] = RegAddr;
    NvOdmOsMemcpy(&s_WriteBuffer[1], value, len);

    TransactionInfo.Address = hDevice->nDevAddr;
    TransactionInfo.Buf = s_WriteBuffer;
    TransactionInfo.Flags = NVODM_I2C_IS_WRITE;
    TransactionInfo.NumBytes = len+1;

    // Write the accelerator RegAddr (from where data is to be read).
    if (NvOdmI2cTransaction(hDevice->hOdmI2C, &TransactionInfo, 1, NVODMECOMPASS_I2C_SPEED_KHZ, 
            I2C_ECOMPASS_TRANSACTION_TIMEOUT) != NvOdmI2cStatus_Success)
        return NV_FALSE;

    return NV_TRUE;
}
static NvBool ConnectSemaphore(NvOdmEcompassHandle hDevice)
{
    NvOdmGpioPinMode mode;
    NvOdmInterruptHandler callback =
        (NvOdmInterruptHandler)GpioInterruptHandler;

    hDevice->hGpioINT = (NvOdmServicesGpioHandle)NvOdmGpioOpen();
    if (!(hDevice->hGpioINT))
    {
        NVODMECOMPASS_PRINTF(("AKM8975 compass driver: NvOdmGpioOpenError \n"));
        return NV_FALSE;
    }

    hDevice->hPinINT = NvOdmGpioAcquirePinHandle(hDevice->hGpioINT,
                           hDevice->GPIOPortINT,
                           hDevice->GPIOPinINT);
    hDevice->SemaphoreForINT = NvOdmOsSemaphoreCreate(0);

    if (!(hDevice->SemaphoreForINT))
    {
        NVODMECOMPASS_PRINTF(( "AKM8975 compass driver: NvOdmOsSemaphoreCreate Error \n"));
        NvOdmGpioClose(hDevice->hGpioINT);
        return NV_FALSE;
    }

    mode = NvOdmGpioPinMode_InputInterruptHigh;
    if (NvOdmGpioInterruptRegister(hDevice->hGpioINT,
        &hDevice->hGpioInterrupt, hDevice->hPinINT, mode, callback,
        hDevice, NV_DEBOUNCE_TIME_MS) == NV_FALSE)
    {
        return NV_FALSE;
    }
	
    if (!(hDevice->hGpioInterrupt))
    {
        NVODMECOMPASS_PRINTF(("AKM8975 compass driver: NvOdm Ecompass NvOdmGpioInterruptRegister Error \n"));
        NvOdmGpioClose(hDevice->hGpioINT);
        NvOdmOsSemaphoreDestroy(hDevice->SemaphoreForINT);
        return NV_FALSE;
    }
    return NV_TRUE;
}
static NvBool AKM8975_Init(NvOdmEcompassHandle hEcompass){

	NvU8 TestVal;
	
	/* Check Connection */
	if(!ReadReg(hEcompass,AK8975_REG_WIA,&TestVal, 1))
		goto error;
	
	if (TestVal!=0x48)
	{
		NVODMECOMPASS_PRINTF(("AKM8975 compass driver : Unknown ID 0x%x \n",TestVal));
		goto error;
	}
	NVODMECOMPASS_PRINTF(("AKM8975 compass driver: ID is 0x%x \n",TestVal));
	NVODMECOMPASS_PRINTF(("AKM8975 compass driver: Init Passed \n"));
	return NV_TRUE;
error:
	NVODMECOMPASS_PRINTF(("AKM8975 compass driver: Init Failed \n"));
	return NV_FALSE;
}
static NvBool
akm8975_ReadXYZ(
	NvOdmEcompassHandle hDevice,
	NvS16* X,
    NvS16* Y,
    NvS16* Z)
{
	NvU8 Data[13];
	NvBool	NewData = 0;
	NvU8 i=0;
	
	if (!ReadReg(hDevice, AK8975_REG_WIA, &Data[0], 1))
		return NV_FALSE;
	
	if (!ReadReg(hDevice, AK8975_REG_INFO, &Data[1], 1))
		return NV_FALSE;
		
	if (!ReadReg(hDevice, AK8975_REG_ST1, &Data[2], 1))
		return NV_FALSE;		

	if (!ReadReg(hDevice, AK8975_REG_ST2, &Data[9], 1))
		return NV_FALSE;			
	
	for (i=0;i<6;i++)
	{
	if (!ReadReg(hDevice, AK8975_REG_HXL+i, &Data[3+i], 1))
		return NV_FALSE;		
	}	

	NewData = ((Data[0] == 0x48)&& !(Data[9] & 0x04) && (Data[2] & 0x01)) ? 1:0;

	NVODMECOMPASS_PRINTF((" X: [%x] [%x] Y: [%x] [%x] Z: [%x] [%x]",	Data[4],Data[3], Data[6], Data[5], Data[8], Data[7]));
	*X = 0xFFFF;
	*Y = 0xFFFF;
	*Z = 0xFFFF;
	return NewData;
}
static void GpioInterruptHandler(void *arg)
{
    NvU32 pinValue;
    NvU8 ret;
    NvU8 buffer[SENSOR_DATA_SIZE];
    NvU8 i;
    NvOdmEcompassHandle hDevice =  (NvOdmEcompassHandle)arg;
    NvOdmGpioGetState(hDevice->hGpioINT, hDevice->hPinINT, &pinValue);

    if (pinValue == 1)
    {
        ret=ReadReg(hDevice, AK8975_REG_ST1, buffer, SENSOR_DATA_SIZE);
        if (ret<0) {
            NVODMECOMPASS_PRINTF(("AKM8975 compass driver: I2C failed\n"));
            return;
        }
        /* Check ST bit */
        if ((buffer[0] & 0x01) != 0x01)
        {
            NVODMECOMPASS_PRINTF(("AKM8975 akm8975_work_func: ST is not set\n"));
            return;
        }
        /* Check ST2 bit */
        if (((buffer[7]&0x04)==0x04)||((buffer[7]&0x08)==0x08))
        {
            NVODMECOMPASS_PRINTF(("AKM8975 akm8975_work_func: Data is Fail\n"));
            return;
        }
        NvOdmOsMemcpy(ecompass_buffer,buffer,SENSOR_DATA_SIZE);
#if 0
        NVODMECOMPASS_PRINTF(("\n"));
        NVODMECOMPASS_PRINTF((" GPIO handle :\n"));
        for (i=0; i<SENSOR_DATA_SIZE; i++) {
            NVODMECOMPASS_PRINTF((" Reg %d : [%02x]\n",i,ecompass_buffer[i]));
        }
#endif
        NvOdmOsSemaphoreSignal(hDevice->SemaphoreForINT);
    }
    NvOdmGpioInterruptDone(hDevice->hGpioInterrupt);
    return;
}
static NvBool
ReadReg(
    NvOdmEcompassHandle hDevice,
    NvU8 RegAddr,
    NvU8* value,
    NvU32 len)
{
	#if 0
    NvOdmI2cTransactionInfo TransactionInfo;

    if ( (NULL == hDevice) || (NULL == value) ||
         (len > I2C_ECOMPASS_PACKET_SIZE-1 ) )
    {
        NVODMECOMPASS_PRINTF(("NvOdmI2c Get Regs Failed, max size is %d bytes\n", I2C_ECOMPASS_PACKET_SIZE-1));
        return NV_FALSE;
    }

    s_WriteBuffer[0] = RegAddr;
    TransactionInfo.Address = hDevice->nDevAddr;
    TransactionInfo.Buf = s_WriteBuffer;
    TransactionInfo.Flags = NVODM_I2C_IS_WRITE;
    TransactionInfo.NumBytes = 1;

    // Write the accelerometor RegAddr (from where data is to be read).
    if (NvOdmI2cTransaction(hDevice->hOdmI2C, &TransactionInfo, 1, NVODMECOMPASS_I2C_SPEED_KHZ,
            I2C_ECOMPASS_TRANSACTION_TIMEOUT) != NvOdmI2cStatus_Success)
        return NV_FALSE;

    s_ReadBuffer[0] = 0;
    TransactionInfo.Address = (hDevice->nDevAddr| 0x1);
    TransactionInfo.Buf = s_ReadBuffer;
    TransactionInfo.Flags = 0;
    TransactionInfo.NumBytes = len;

    //Read the data from the eeprom at the specified RegAddr
    if (NvOdmI2cTransaction(hDevice->hOdmI2C, &TransactionInfo, 1, NVODMECOMPASS_I2C_SPEED_KHZ,
            I2C_ECOMPASS_TRANSACTION_TIMEOUT) != NvOdmI2cStatus_Success)
        return NV_FALSE;

    NvOdmOsMemcpy(value, &s_ReadBuffer[0], len);
    return NV_TRUE;
	#else
	NvU32 i;
	NvOdmI2cStatus  status = NvOdmI2cStatus_Success;
	NvOdmI2cTransactionInfo TransactionInfo[2];
	
	if ( (NULL == hDevice) || (NULL == value) ||
         (len > I2C_ECOMPASS_PACKET_SIZE-1 ) )
    {
        NVODMECOMPASS_PRINTF(("NvOdmI2c Get Regs Failed, max size is %d bytes\n", I2C_ECOMPASS_PACKET_SIZE-1));
        return NV_FALSE;
    }
	
	for (i=0; i<NVODMECOMPASS_I2C_RETRY_CNT; i++)
	{
		NvU32 TransactionCount = 0;
		
		s_WriteBuffer[0] = RegAddr;
		TransactionInfo[TransactionCount].Address = hDevice->nDevAddr;
		TransactionInfo[TransactionCount].Buf = &s_WriteBuffer[0];
		TransactionInfo[TransactionCount].Flags =
			NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START;
		TransactionInfo[TransactionCount++].NumBytes = 1;
		
		s_ReadBuffer[0] = 0;
		TransactionInfo[TransactionCount].Address = (hDevice->nDevAddr | 0x1);
		TransactionInfo[TransactionCount].Buf = &s_ReadBuffer[0];
		TransactionInfo[TransactionCount].Flags = 0;
		TransactionInfo[TransactionCount++].NumBytes = len;	

		status = NvOdmI2cTransaction(hDevice->hOdmI2C, &TransactionInfo[0],
			TransactionCount, NVODMECOMPASS_I2C_SPEED_KHZ, NV_WAIT_INFINITE);	
		
		if (status == NvOdmI2cStatus_Success)
		{
			NvOdmOsMemcpy(value, &s_ReadBuffer[0], len);
			return NV_TRUE;
		}
	}
	
    // Transaction Error
    switch (status)
    {
        case NvOdmI2cStatus_Timeout:
            NVODMECOMPASS_PRINTF(("NvOdmEcompassI2cRead Failed: Timeout\n"));
            break;
        case NvOdmI2cStatus_SlaveNotFound:
        default:
            NVODMECOMPASS_PRINTF(("NvOdmEcompassI2cRead Failed: SlaveNotFound\n"));
            break;
    }
    return NV_FALSE;	
	#endif
}