#include "IOI2CAD741x.h"
#define super IOI2CDevice
OSDefineMetaClassAndStructors(IOI2CAD741x, IOI2CDevice)
void IOI2CAD741x::free( void )
{
super::free();
}
bool IOI2CAD741x::start( IOService *nub )
{
IOService *childNub;
OSArray * nubArray;
DLOG("+IOI2CAD741x::start - entered\n");
if (!fGetSensorValueSym)
fGetSensorValueSym = OSSymbol::withCString("getSensorValue");
if (!super::start(nub))
return(false);
if (softReset() != kIOReturnSuccess)
{
DLOG("-IOI2CAD741x@%lx::start failed to soft-reset device\n", getI2CAddress());
freeI2CResources();
return(false);
}
nubArray = parseSensorParamsAndCreateNubs( nub );
if (nubArray == NULL || nubArray->getCount() == 0)
{
DLOG("-IOI2CAD741x@%lx::start no thermal sensors found\n", getI2CAddress());
if (nubArray)
nubArray->release();
freeI2CResources();
return(false);
}
for (unsigned int index = 0; index < nubArray->getCount(); index++)
{
childNub = OSDynamicCast(IOService, nubArray->getObject(index));
if (childNub) childNub->registerService();
}
nubArray->release();
registerService();
DLOG("-IOI2CAD741x@%lx::start\n", getI2CAddress());
return(true);
}
void IOI2CAD741x::stop( IOService *nub )
{
if (fGetSensorValueSym) { fGetSensorValueSym->release(); fGetSensorValueSym = NULL; }
super::stop( nub );
}
IOReturn IOI2CAD741x::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction, void *param1, void *param2,
void *param3, void *param4)
{
UInt32 id = (UInt32)param1;
UInt32 *value_buf = (UInt32 *)param2;
SInt32 *temp_buf = (SInt32 *)param2;
bool found = false;
UInt8 i;
if (functionName->isEqualTo(fGetSensorValueSym) == true)
{
if (isI2COffline() == true)
{
DLOG("IOI2CAD741x@%lx::callPlatformFunction I2C OFFLINE\n", getI2CAddress());
return(kIOReturnOffline);
}
if (temp_buf == NULL)
{
DLOG("IOI2CAD741x@%lx::callPlatformFunction BAD ARGS\n", getI2CAddress());
return(kIOReturnBadArgument);
}
for (i=0; i<5; i++)
{
if (id == fHWSensorIDMap[i])
{
found = true;
break;
}
}
if (found)
{
if (i == 0)
return(getTemperature(temp_buf));
else
return(getADC(i, value_buf));
}
}
return(super::callPlatformFunction(functionName, waitForFunction,
param1, param2, param3, param4));
}
OSArray *IOI2CAD741x::parseSensorParamsAndCreateNubs(IOService *nub)
{
IOService *childNub;
OSData *tmp_osdata, *tempNubName, *adcNubName;
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];
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorParamsVersionKey));
if (tmp_osdata == NULL)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs no param version\n");
return(NULL);
}
version = *((UInt32 *)tmp_osdata->getBytesNoCopy());
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorIDKey));
if (tmp_osdata == NULL)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs no ids\n");
return(NULL);
}
n_sensors = tmp_osdata->getLength() / sizeof(UInt32);
if (n_sensors > 5)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs too many sensors %u\n", n_sensors);
return(NULL);
}
id = (UInt32 *)tmp_osdata->getBytesNoCopy();
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorZoneKey));
if (tmp_osdata == NULL)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs no zones\n");
return(NULL);
}
zone = (UInt32 *)tmp_osdata->getBytesNoCopy();
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorTypeKey));
if (tmp_osdata == NULL)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs no types\n");
return(NULL);
}
type = (const char *)tmp_osdata->getBytesNoCopy();
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorLocationKey));
if (tmp_osdata == NULL)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs no locations\n");
return(NULL);
}
location = (const char *)tmp_osdata->getBytesNoCopy();
tmp_osdata = OSDynamicCast(OSData,
nub->getProperty(kDTSensorPollingPeriodKey));
if (tmp_osdata != NULL)
{
polling_period = (UInt32 *)tmp_osdata->getBytesNoCopy();
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs polling period %lx\n", polling_period);
}
strcpy(work, kHWTempSensorNubName);
tempNubName = OSData::withBytes(work, strlen(work) + 1);
if (tempNubName == NULL) return(0);
strcpy(work, kHWADCSensorNubName);
adcNubName = OSData::withBytes(work, strlen(work) + 1);
if (adcNubName == NULL) return(0);
for (i=0; i<n_sensors; i++)
{
DLOG("IOI2CAD741x::parseSensorParamsAndCreateNubs child nub %u\n", i);
childNub = OSDynamicCast(IOService,
OSMetaClass::allocClassWithName("IOService"));
if (!childNub || !childNub->init())
continue;
childNub->attach(this);
fHWSensorIDMap[i] = id[i];
if (strcmp(type, "adc") == 0)
{
childNub->setName(kHWADCSensorNubName);
childNub->setProperty("name", adcNubName);
childNub->setProperty("compatible", adcNubName);
childNub->setProperty("device_type", adcNubName);
}
else {
childNub->setName(kHWTempSensorNubName);
childNub->setProperty("name", tempNubName);
childNub->setProperty("compatible", tempNubName);
childNub->setProperty("device_type", tempNubName);
}
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 && polling_period[i] != kHWSensorPollingPeriodNULL)
childNub->setProperty(kHWSensorPollingPeriodKey, &polling_period[i],
sizeof(UInt32));
if (nubArray == NULL)
{
nubArray = OSArray::withObjects((const OSObject **) &childNub, 1);
}
else
{
nubArray->setObject( childNub );
}
}
tempNubName->release();
adcNubName->release();
return(nubArray);
}
#pragma mark -
#pragma mark *** Software Reset ***
#pragma mark -
IOReturn IOI2CAD741x::softReset( void )
{
IOReturn status;
UInt8 val;
UInt32 key;
if (kIOReturnSuccess == (status = lockI2CBus(&key)))
{
val = 0;
if (kIOReturnSuccess == (status = writeI2C( kConfig1Reg, &val, 1, key )))
{
val = 0;
if (kIOReturnSuccess == (status = writeI2C( kConfig2Reg, &val, 1, key )))
{
if (kIOReturnSuccess != (status = readI2C( kConfig1Reg, &val, 1, key )))
DLOG("IOI2CAD741x::softReset failed to read back cfg1 reg\n");
}
else
DLOG("IOI2CAD741x::softReset failed to write cfg2 reg\n");
}
else
DLOG("IOI2CAD741x::softReset failed to write cfg1 reg\n");
unlockI2CBus(key);
}
return status;
}
#pragma mark -
#pragma mark *** Read Sensor Channels ***
#pragma mark -
IOReturn IOI2CAD741x::getTemperature( SInt32 * temp )
{
IOReturn status;
UInt8 bytes[2];
SInt16 reading;
*temp = -1;
if (kIOReturnSuccess != (status = readI2C( kTempValueReg, bytes, 2 )))
{
DLOG("IOI2CAD741x::getTemperature read temp failed!\n");
*temp = -1;
return status;
}
DLOG("IOI2CAD741x@%lx::getTemperature got bytes 0x%02X 0x%02X\n", getI2CAddress(), bytes[0], bytes[1]);
reading = *((SInt16 *) bytes);
*temp = ( ( ( SInt16 ) ( reading & 0xFFC0 ) ) << 8 );
return status;
}
IOReturn IOI2CAD741x::getADC( UInt8 channel, UInt32 * sample )
{
IOReturn status;
UInt8 cfg1, tmpByte, bytes[2];
UInt16 rawSample;
UInt32 key;
if (channel < kAD1Channel || channel > kAD4Channel)
{
DLOG("IOI2CAD741x::getADC invalid channel\n");
return(kIOReturnBadArgument);
}
if (kIOReturnSuccess == (status = lockI2CBus(&key)))
{
status = readI2C( kConfig1Reg, &cfg1, 1, key );
if (kIOReturnSuccess != status)
DLOG("IOI2CAD741x::getADC read cfg1 failed!\n");
else
{
tmpByte = channel << kCfg1ChannelShift;
cfg1 = (cfg1 & ~kCfg1ChannelMask) | (tmpByte & kCfg1ChannelMask);
status = writeI2C( kConfig1Reg, &cfg1, 1, key );
}
if (kIOReturnSuccess != status)
DLOG("IOI2CAD741x::getADC write cfg1 failed!\n");
else
status = readI2C( kADCReg, bytes, 2, key );
if (kIOReturnSuccess != status)
DLOG("IOI2CAD741x::getADC read adc reg failed!\n");
unlockI2CBus(key);
}
else
DLOG("IOI2CAD741x::getADC error locking bus!\n");
if (kIOReturnSuccess != status)
{
*sample = 0xFFFFFFFF;
return status;
}
DLOG("IOI2CAD741x@%lx::getADC ch:%x got bytes 0x%02X 0x%02X\n", getI2CAddress(), channel, bytes[0], bytes[1]);
rawSample = *((UInt16 *) bytes);
*sample = ((UInt32)rawSample) >> 6; return status;
}