#include "IOI2CLM7x.h"
#define LM7x_DEBUG 0
#if (defined(LM7x_DEBUG) && LM7x_DEBUG)
#define DLOG(fmt, args...) kprintf(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#define ERRLOG(fmt, args...) kprintf(fmt, ## args)
#define super IOI2CDevice
OSDefineMetaClassAndStructors(IOI2CLM7x, IOI2CDevice)
bool IOI2CLM7x::start(
IOService *provider)
{
IOService *childNub;
OSArray *nubArray;
DLOG("+IOI2CLM7x::start\n");
fRegistersAreSaved = false;
sGetSensorValueSym = OSSymbol::withCString("getSensorValue");
if ( !(super::start(provider)) )
return false;
if (fInitHWFailed)
{
ERRLOG("-IOI2CLM7x::start(0x%lx) device not responding\n", getI2CAddress());
freeI2CResources();
return false;
}
nubArray = parseSensorParamsAndCreateNubs(fProvider);
if (nubArray == NULL || nubArray->getCount() == 0)
{
ERRLOG("-IOI2CLM7x::start(0x%lx) no thermal sensors found\n", getI2CAddress());
if (nubArray)
nubArray->release();
freeI2CResources();
return false;
}
registerService();
for (unsigned int index = 0; index < nubArray->getCount(); index++)
{
childNub = OSDynamicCast(IOService, nubArray->getObject(index));
if (childNub)
childNub->registerService();
}
nubArray->release();
DLOG("-IOI2CLM7x::start(0x%lx)\n", getI2CAddress());
return true;
}
void IOI2CLM7x::free(void)
{
if (sGetSensorValueSym) { sGetSensorValueSym->release(); sGetSensorValueSym = 0; }
super::free();
}
IOReturn IOI2CLM7x::initHW(void)
{
IOReturn status;
UInt8 cfgReg;
UInt32 key;
DLOG("IOI2CLM7x::initHW(0x%x) entered.\n", getI2CAddress());
if (kIOReturnSuccess == (status = lockI2CBus(&key)))
{
if (kIOReturnSuccess == (status = readI2C(kConfigurationReg, &cfgReg, 1, key)))
{
cfgReg |= (kCfgRegR0 | kCfgRegR1);
status = writeI2C(kConfigurationReg, &cfgReg, 1, key);
}
unlockI2CBus(key);
}
if (kIOReturnSuccess != status)
fInitHWFailed = true;
return kIOReturnSuccess;
}
IOReturn IOI2CLM7x::getTemperature(SInt32 *temperature)
{
IOReturn status;
UInt8 bytes[2];
SInt16 reading;
status = readI2C((UInt8)kTemperatureReg, bytes, 2);
if(status != kIOReturnSuccess)
{
ERRLOG("IOI2CLM7x::getTempertaure(0x%x) readI2C failed.\n", getI2CAddress());
return status;
}
reading = *((SInt16 *) bytes);
*temperature = (((SInt32)(reading & 0xFF80)) << 8);
return kIOReturnSuccess;
}
#pragma mark -
#pragma mark *** Platform Functions ***
#pragma mark -
IOReturn IOI2CLM7x::callPlatformFunction(
const OSSymbol *functionName,
bool waitForFunction,
void *param1,
void *param2,
void *param3,
void *param4)
{
UInt32 id = (UInt32)param1;
SInt32 *value = (SInt32 *)param2;
DLOG("IOI2CLM7x::callPlatformFunction(0x%x) %s %s %08lx %08lx %08lx %08lx\n",
getI2CAddress(),
functionName->getCStringNoCopy(), waitForFunction ? "TRUE" : "FALSE",
(UInt32)param1,
(UInt32)param2,
(UInt32)param3,
(UInt32)param4);
if (functionName->isEqualTo(sGetSensorValueSym) == TRUE)
{
if (isI2COffline())
return kIOReturnOffline;
if (id == fHWSensorIDMap[0])
return(getTemperature(value));
}
return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
}
OSArray *IOI2CLM7x::parseSensorParamsAndCreateNubs(IOService *nub)
{
IOService *childNub;
OSData *tempOSData;
OSArray *nubArray = NULL;
unsigned i, n_sensors = 0;
UInt32 version, *id = NULL, *zone = NULL, *polling_period = NULL;
const char *type = NULL, *location = NULL;
char work[32];
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorParamsVersionKey));
if (tempOSData == NULL)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) no param version\n", getI2CAddress());
return(NULL);
}
version = *((UInt32 *)tempOSData->getBytesNoCopy());
if (version != 1)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) version != 1\n", getI2CAddress());
return(NULL);
}
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorIDKey));
if (tempOSData == NULL)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) no ids\n", getI2CAddress());
return(NULL);
}
n_sensors = tempOSData->getLength() / sizeof(UInt32);
if (n_sensors > 1)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) too many sensors %u\n", getI2CAddress(), n_sensors);
return(NULL);
}
id = (UInt32 *)tempOSData->getBytesNoCopy();
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorZoneKey));
if (tempOSData == NULL)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) no zones\n", getI2CAddress());
return(NULL);
}
zone = (UInt32 *)tempOSData->getBytesNoCopy();
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorTypeKey));
if (tempOSData == NULL)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) no types\n", getI2CAddress());
return(NULL);
}
type = (const char *)tempOSData->getBytesNoCopy();
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorLocationKey));
if (tempOSData == NULL)
{
ERRLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) no locations\n", getI2CAddress());
return(NULL);
}
location = (const char *)tempOSData->getBytesNoCopy();
tempOSData = OSDynamicCast(OSData, nub->getProperty(kDTSensorPollingPeriodKey));
if (tempOSData != NULL)
{
polling_period = (UInt32 *)tempOSData->getBytesNoCopy();
DLOG("IOI2CLM7x::parseSensorParamsAndCreateNubs(0x%x) polling period %lu\n", getI2CAddress(), polling_period);
}
strcpy(work, kHWSensorNubName);
tempOSData = OSData::withBytes(work, strlen(work) + 1);
if (tempOSData == NULL)
{
return(0);
}
for (i=0; i<n_sensors; i++)
{
childNub = OSDynamicCast(IOService, OSMetaClass::allocClassWithName("IOService"));
if (!childNub || !childNub->init())
continue;
childNub->attach(this);
fHWSensorIDMap[i] = id[i];
childNub->setName(kHWSensorNubName);
childNub->setProperty("name", tempOSData);
childNub->setProperty("compatible", tempOSData);
childNub->setProperty("device_type", tempOSData);
childNub->setProperty(kHWSensorParamsVersionKey, &version, sizeof(UInt32));
childNub->setProperty(kHWSensorIDKey, &id[i], sizeof(UInt32));
childNub->setProperty(kHWSensorZoneKey, &zone[i], sizeof(UInt32));
childNub->setProperty(kHWSensorTypeKey, type);
type += strlen(type) + 1;
childNub->setProperty(kHWSensorLocationKey, location);
location += strlen(location) + 1;
if ( polling_period )
{
childNub->setProperty(kHWSensorPollingPeriodKey, &polling_period[i], sizeof(UInt32));
}
if (nubArray == NULL)
{
nubArray = OSArray::withObjects((const OSObject **) &childNub, 1);
}
else
{
nubArray->setObject( childNub );
}
}
tempOSData->release();
return(nubArray);
}
#pragma mark -
#pragma mark *** Power Management ***
#pragma mark -
void IOI2CLM7x::processPowerEvent(UInt32 eventType)
{
switch (eventType)
{
case kI2CPowerEvent_OFF:
case kI2CPowerEvent_SLEEP:
if ( saveRegisters() != kIOReturnSuccess )
ERRLOG("IOI2CLM7x::processPowerEvent(0x%x) failed to save registers.\n", getI2CAddress());
else
fRegistersAreSaved = true;
break;
case kI2CPowerEvent_ON:
case kI2CPowerEvent_WAKE:
if (fRegistersAreSaved == true)
{
if ( restoreRegisters() != kIOReturnSuccess )
ERRLOG("IOI2CLM7x::processPowerEvent(0x%x) failed to restore registers.\n", getI2CAddress());
fRegistersAreSaved = false;
}
break;
case kI2CPowerEvent_STARTUP:
if( initHW() != kIOReturnSuccess )
ERRLOG("-IOI2CLM7x::processPowerEvent(0x%lx) failed to initialize sensor.\n", getI2CAddress());
break;
}
}
IOReturn IOI2CLM7x::saveRegisters(void)
{
IOReturn status;
DLOG("+IOI2CLM7x::saveRegisters(0x%x) entered.\n", getI2CAddress());
status = readI2C(kConfigurationReg, (UInt8 *)&savedRegisters.Configuration, 1);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::saveRegisters(0x%x) readI2C failed.\n", getI2CAddress());
return status;
}
status = readI2C(kT_hystReg, (UInt8 *)&savedRegisters.Thyst, 2);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::saveRegisters(0x%x) readI2C failed.\n", getI2CAddress());
return status;
}
status = readI2C(kT_osReg, (UInt8 *)&savedRegisters.Tos, 2);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::saveRegisters(0x%x) readI2C failed.\n", getI2CAddress());
return status;
}
DLOG("-IOI2CLM7x::saveRegisters(0x%x) done.\n", getI2CAddress());
return status;
}
IOReturn IOI2CLM7x::restoreRegisters(void)
{
IOReturn status;
DLOG("+IOI2CLM7x::restoreRegisters(0x%x) entered.\n", getI2CAddress());
status = writeI2C(kConfigurationReg, (UInt8 *)&savedRegisters.Configuration, 1);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::restoreRegisters(0x%x) writeI2C failed.\n", getI2CAddress());
return status;
}
status = writeI2C(kT_hystReg, (UInt8 *)&savedRegisters.Thyst, 2);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::restoreRegisters(0x%x) writeI2C failed.\n", getI2CAddress());
return status;
}
status = writeI2C(kT_osReg, (UInt8 *)&savedRegisters.Tos, 2);
if(status != kIOReturnSuccess)
{
ERRLOG("-IOI2CLM7x::restoreRegisters(0x%x) writeI2C failed.\n", getI2CAddress());
return status;
}
DLOG("-IOI2CLM7x::restoreRegisters(0x%x) done.\n", getI2CAddress());
return status;
}