static void Adt7461Isr(void* arg) { NvU8 Data; ADT7461PrivData* pPrivData = (ADT7461PrivData*)arg; NvOdmInterruptHandler volatile Callback = pPrivData->Callback; void* volatile CallbackArg = pPrivData->CallbackArg; const ADT7461RegisterInfo* pReg = NULL; if (Callback && CallbackArg) { Callback(CallbackArg); } #if ADT7461_ALERT_DEBOUNCE // New range limits set by callback are not guaranteed to take effect // before the next temperature conversion is completed, and interrupt // can not be cleared until then. Hence, the debounce delay below. NvOdmOsSleepMS(s_Adt7461SampleIntervalsMS[pPrivData->ShadowRate] + s_Adt7461ConversionTimesMS[pPrivData->ShadowRate] + 1); #endif // Read status and ARA to finish clearing interrupt after callback pReg = &pPrivData->pDeviceInfo->Status; (void)Adt7461ReadReg(pPrivData, pReg, &Data); Adt7461ReadAra(pPrivData); // Re-enable interrupt if (pPrivData->hGpioIntr) NvOdmGpioInterruptDone(pPrivData->hGpioIntr); }
NvBool Adt7461TemperatureGet( NvOdmTmonDeviceHandle hTmon, NvOdmTmonZoneID ZoneId, NvS32* pDegreesC) { NvU8 Data; NvBool ExtRange; ADT7461ChannelID ChannelId; ADT7461PrivData* pPrivData; const ADT7461RegisterInfo* pReg; NV_ASSERT(hTmon && hTmon->pPrivate && pDegreesC); pPrivData = hTmon->pPrivate; ExtRange = ((pPrivData->ShadowConfig & ADT7461ConfigBits_ExtendedRange) != 0); ChannelId = pPrivData->ConnectivityMap[ZoneId]; pReg = &pPrivData->pDeviceInfo->Channels[ChannelId].Tdata; if(!Adt7461ReadReg(pPrivData, pReg, &Data)) return NV_FALSE; *pDegreesC = ADT7461_T_DATA_TO_VALUE(ExtRange, Data); /* NVODM_ADT7461_PRINTF(("Adt7461TemperatureGet ChannelId=%d,ExtRange=%d,Data=%d,ZoneId=%d,t=%d\n",ChannelId,ExtRange,Data,ZoneId,*pDegreesC)); pReg = &pPrivData->pDeviceInfo->Channels[1].Tdata; if(!Adt7461ReadReg(pPrivData, pReg, &Data)) return NV_FALSE; NVODM_ADT7461_PRINTF(("Adt7461TemperatureGet ChannelId=1,Data=%d\n",Data));//*/ return NV_TRUE; }
static NvBool Adt7461ConfigureSampleInterval( ADT7461PrivData* pPrivData, NvBool OdmProtected, NvS32* pTargetMs) { NvU8 i; NvS32 Delta; const ADT7461RegisterInfo* pReg = &pPrivData->pDeviceInfo->Rate; if (OdmProtected || ((*pTargetMs) == ODM_TMON_PARAMETER_UNSPECIFIED)) { // Read ADT7461 rate register (fail the call if returned data // does not make sense) if(!Adt7461ReadReg(pPrivData, pReg, &i)) return NV_FALSE; if (i >= NV_ARRAY_SIZE(s_Adt7461SampleIntervalsMS)) return NV_FALSE; } else { // Find and set the best floor approximation of the target sample // interval. Note the descending order of sample intervals array. for (i = 0; i < NV_ARRAY_SIZE(s_Adt7461SampleIntervalsMS); i++) { Delta = (*pTargetMs) - s_Adt7461SampleIntervalsMS[i]; if(Delta >= 0) break; } if (i == NV_ARRAY_SIZE(s_Adt7461SampleIntervalsMS)) i--; // min interval is the best we can do if(!Adt7461WriteReg(pPrivData, pReg, i)) return NV_FALSE; pPrivData->ShadowRate = i; } *pTargetMs = s_Adt7461SampleIntervalsMS[i]; return NV_TRUE; }
NvBool Adt7461ParameterConfig( NvOdmTmonDeviceHandle hTmon, NvOdmTmonZoneID ZoneId, NvOdmTmonConfigParam ParamId, NvS32* pSetting) { NvU8 Data; NvBool ExtRange, OdmProtected; ADT7461PrivData* pPrivData; const ADT7461RegisterInfo* pReg; const ADT7461ChannelInfo* pChannel; NV_ASSERT(hTmon && hTmon->pPrivate && pSetting); pPrivData = hTmon->pPrivate; #if PRE_ER_GMT_THERMALSENSOR ExtRange = 0; /* not support ADT thermal sensor*/ #else ExtRange = ((pPrivData->ShadowConfig & ADT7461ConfigBits_ExtendedRange) != 0); #endif pChannel = &pPrivData->pDeviceInfo->Channels[( pPrivData->ConnectivityMap[ZoneId])]; switch (ParamId) { case NvOdmTmonConfigParam_IntrLimitHigh: #if PRE_ER_WORKAROUND return NV_TRUE; #endif pReg = &pChannel->IntrLimitHigh; OdmProtected = pChannel->ChannelPolicy.IntrLimitsOdmProtected; break; case NvOdmTmonConfigParam_IntrLimitLow: #if PRE_ER_WORKAROUND return NV_TRUE; #endif pReg = &pChannel->IntrLimitLow; OdmProtected = pChannel->ChannelPolicy.IntrLimitsOdmProtected; break; case NvOdmTmonConfigParam_HwLimitCrit: #if PRE_ER_WORKAROUND return NV_TRUE; #endif pReg = &pChannel->ComparatorLimit; OdmProtected = pChannel->ChannelPolicy.HwLimitCritOdmProtected; break; case NvOdmTmonConfigParam_SampleMs: OdmProtected = pChannel->ChannelPolicy.RateOdmProtected; return Adt7461ConfigureSampleInterval( pPrivData, OdmProtected, pSetting); default: // unsupported parameter *pSetting = ODM_TMON_PARAMETER_UNSPECIFIED; return NV_TRUE; } // Common processing for temperature limits configuration if ((OdmProtected) || ((*pSetting) == ODM_TMON_PARAMETER_UNSPECIFIED)) { // Read ADT7461 register and convert data to current parameter value if(!Adt7461ReadReg(pPrivData, pReg, &Data)) return NV_FALSE; *pSetting = ADT7461_T_DATA_TO_VALUE(ExtRange, Data); } else { // Clip target setting to temperature range if ((*pSetting) > ADT7461_T_RANGE_LIMIT_HIGH(ExtRange)) *pSetting = ADT7461_T_RANGE_LIMIT_HIGH(ExtRange); else if ((*pSetting) < ADT7461_T_RANGE_LIMIT_LOW(ExtRange)) *pSetting = ADT7461_T_RANGE_LIMIT_LOW(ExtRange); // Convert new configuration setting and write to ADT7461 register Data = ADT7461_T_VALUE_TO_DATA(ExtRange, *pSetting); if(!Adt7461WriteReg(pPrivData, pReg, Data)) return NV_FALSE; } return NV_TRUE; }
NvBool Adt7461TemperatureGet( NvOdmTmonDeviceHandle hTmon, NvOdmTmonZoneID ZoneId, NvS32* pDegreesC) { NvU8 Data; NvBool ExtRange; ADT7461ChannelID ChannelId; ADT7461PrivData* pPrivData; const ADT7461RegisterInfo* pReg; #if (DEBUG_THERMALSENSOR || CONFIG_TEGRA_TMON_PROC) ADT7461RegisterInfo reg; int i; #endif NV_ASSERT(hTmon && hTmon->pPrivate && pDegreesC); pPrivData = hTmon->pPrivate; #if PRE_ER_GMT_THERMALSENSOR ExtRange = 0; /* not support ADT thermal sensor*/ #else ExtRange = ((pPrivData->ShadowConfig & ADT7461ConfigBits_ExtendedRange) != 0); #endif ChannelId = pPrivData->ConnectivityMap[ZoneId]; pReg = &pPrivData->pDeviceInfo->Channels[ChannelId].Tdata; if(!Adt7461ReadReg(pPrivData, pReg, &Data)) return NV_FALSE; *pDegreesC = ADT7461_T_DATA_TO_VALUE(ExtRange, Data); #if CONFIG_TEGRA_TMON_PROC reg.RdAddr = pReg->RdAddr - 1; /* local temperature register address */ reg.WrAddr = pReg->WrAddr - 1; if(!Adt7461ReadReg(pPrivData, ®, &Data)) return NV_FALSE; /* export temperature to /proc/localtmon */ localTemperatureC = (NvS32)ADT7461_T_DATA_TO_VALUE(ExtRange, Data); #endif #if DEBUG_THERMALSENSOR printk("ChannelId:0x%x\n", ChannelId); printk("Temperature Data register pReg:0x%x\n", pReg); printk("Temperature *pDegreesC:0x%x\n", *pDegreesC); i = 0 ; reg.RdAddr = pReg->RdAddr - 1; reg.WrAddr = pReg->WrAddr - 1; while(i < 40 ){ if(!Adt7461ReadReg(pPrivData, ®, &Data)) return NV_FALSE; printk("register pReg:0x%x\n", reg.RdAddr); printk("Data:0x%x, %d\n", ADT7461_T_DATA_TO_VALUE(ExtRange, Data), (NvS32)ADT7461_T_DATA_TO_VALUE(ExtRange, Data)); i++; reg.RdAddr++; } #endif return NV_TRUE; }
NvBool Adt7461Init(NvOdmTmonDeviceHandle hTmon) { NvU8 Data; NvBool ExtRange; NvU32 i = 0; NvU32 I2cInstance = 0; NvOdmIoModule I2cModule = NvOdmIoModule_Num; // Inavlid module const ADT7461RegisterInfo* pReg = NULL; ADT7461PrivData* pPrivData = NULL; NV_ASSERT(hTmon && hTmon->pConn && hTmon->pConn->AddressList); // Allocate and clear priavte data pPrivData = (ADT7461PrivData*) NvOdmOsAlloc(sizeof(ADT7461PrivData)); if (pPrivData == NULL) { NVODM_ADT7461_PRINTF(("ADT7461: Error Allocating PrivData. \n")); return NV_FALSE; } NvOdmOsMemset(pPrivData, 0, sizeof(ADT7461PrivData)); hTmon->pPrivate = pPrivData; // Register for PMU services pPrivData->hOdmPmuSevice = NvOdmServicesPmuOpen(); if (pPrivData->hOdmPmuSevice == NULL) { NVODM_ADT7461_PRINTF(("ADT7461: Error Open PMU service. \n")); goto fail; } // Register for GPIO services pPrivData->hGpio = NvOdmGpioOpen(); if (pPrivData->hOdmPmuSevice == NULL) { NVODM_ADT7461_PRINTF(("ADT7461: Error Open GPIO service. \n")); goto fail; } /* * Parse connectivity data: turn On power to the device, acquire I2C * interface and GPIO interrupt (optional); map device channels to * thermal zones */ for (i = 0; i < hTmon->pConn->NumAddress; i ++) { const NvOdmIoAddress* pIoAddress = &hTmon->pConn->AddressList[i]; if (pIoAddress->Interface == NvOdmIoModule_I2c_Pmu) { I2cModule = NvOdmIoModule_I2c_Pmu; I2cInstance = pIoAddress->Instance; NV_ASSERT(pIoAddress->Address != 0); pPrivData->DeviceI2cAddr = pIoAddress->Address; } else if (pIoAddress->Interface == NvOdmIoModule_Tsense) { NV_ASSERT(pIoAddress->Instance < NvOdmTmonZoneID_Num); NV_ASSERT(pIoAddress->Address < ADT7461ChannelID_Num); pPrivData->ConnectivityMap[pIoAddress->Instance] = pIoAddress->Address; } else if (pIoAddress->Interface == NvOdmIoModule_Vdd) { NvU32 usec = 0; NvU32 RailAddress = pIoAddress->Address; NvOdmServicesPmuVddRailCapabilities RailCapabilities; NvOdmServicesPmuGetCapabilities( pPrivData->hOdmPmuSevice, RailAddress, &RailCapabilities); NvOdmServicesPmuSetVoltage(pPrivData->hOdmPmuSevice, RailAddress, RailCapabilities.requestMilliVolts, &usec); NvOdmOsWaitUS(usec + (ADT7461_POWERUP_DELAY_MS * 1000)); } else if (pIoAddress->Interface == NvOdmIoModule_Gpio) { NvU32 port = pIoAddress->Instance; NvU32 pin = pIoAddress->Address; pPrivData->hGpioPin = NvOdmGpioAcquirePinHandle( pPrivData->hGpio, port, pin); } } NV_ASSERT(I2cModule == NvOdmIoModule_I2c_Pmu); pPrivData->hOdmI2C = NvOdmI2cOpen(I2cModule, I2cInstance); if (pPrivData->hOdmI2C == NULL) { NVODM_ADT7461_PRINTF(("ADT7461: Error Open I2C device. \n")); goto fail; } /* * Initialize device info and configuration. Force standby mode to avoid * glitch on shutdown comparator output when temperature range and/or * comparator limit is changing during initialization. The Adt7461Run() * call from the hal that follows initialization will switch device to * run mode and re-start temperature monitoring (note that out of limit * interrupt is always masked during and after initialization) */ pPrivData->pDeviceInfo = &s_Adt7461Info; pPrivData->ShadowRegPtr = ADT7461_INVALID_ADDR; pReg = &pPrivData->pDeviceInfo->Config; if (!Adt7461ReadReg(pPrivData, pReg, &Data)) goto fail; if ((Data & ADT7461ConfigBits_ExtendedRange) != (ADT7461_INITIAL_CONFIG & ADT7461ConfigBits_ExtendedRange)) { // Only switch from standard to extended range is supported NV_ASSERT((Data & ADT7461ConfigBits_ExtendedRange) == 0); Data |= ADT7461ConfigBits_Standby; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; } Data = ADT7461_INITIAL_CONFIG | ADT7461ConfigBits_Standby; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; pPrivData->ShadowConfig = Data; #if PRE_ER_GMT_THERMALSENSOR ExtRange = 0; /* not support ADT thermal sensor*/ #else ExtRange = ((Data & ADT7461ConfigBits_ExtendedRange) != 0); #endif // Program shutdown comparators settings Data = ADT7461_T_VALUE_TO_DATA( ExtRange, ADT7461_ODM_LOCAL_COMPARATOR_LIMIT_VALUE); pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Local].ComparatorLimit; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; Data = ADT7461_T_VALUE_TO_DATA( ExtRange, ADT7461_ODM_REMOTE_COMPARATOR_LIMIT_VALUE); pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Remote].ComparatorLimit; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; // Set interrupt limits to the range boundaries to prevent out of limit // interrupt Data = ADT7461_T_VALUE_TO_DATA( ExtRange, ADT7461_T_RANGE_LIMIT_HIGH(ExtRange)); pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Local].IntrLimitHigh; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Remote].IntrLimitHigh; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; Data = ADT7461_T_VALUE_TO_DATA( ExtRange, ADT7461_T_RANGE_LIMIT_LOW(ExtRange)); pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Local].IntrLimitLow; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Remote].IntrLimitLow; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; // Set initial rate Data = ADT7461_INITIAL_RATE_SETTING; pReg = &pPrivData->pDeviceInfo->Rate; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; pPrivData->ShadowRate = Data; // Set remote channel offset (8-bit 2's complement value for any range) Data = ((NvU8)ADT7461_ODM_REMOTE_OFFSET_VALUE); pReg = &pPrivData->pDeviceInfo->Channels[ ADT7461ChannelID_Remote].Toffset; if(!Adt7461WriteReg(pPrivData, pReg, Data)) goto fail; // Read ADT7461 status and ARA (clear pending Alert interrupt, if any) pReg = &pPrivData->pDeviceInfo->Status; if (!Adt7461ReadReg(pPrivData, pReg, &Data)) goto fail; // TODO: check open remote circuit error Adt7461ReadAra(pPrivData); return NV_TRUE; fail: Adt7461FreePrivData(pPrivData); hTmon->pPrivate = NULL; return NV_FALSE; }