/* This function should return the chip type .. */ int adt7473_detect(I2CDevPtr dev) { I2CByte man_id, dev_id, chip_id; xf86I2CReadByte(dev, ADT7473_REG_MAN_ID, &man_id); xf86I2CReadByte(dev, ADT7473_REG_DEVID2, &dev_id); if (man_id != AD_MAN_ID || (dev_id & 0xf8) != 0x68) return 0; xf86I2CReadByte(dev, ADT7473_REG_CHIP_ID, &chip_id); if (chip_id == 0x73) { dev->chip_id = ADT7473; dev->chip_name = (char*)STRDUP("Analog Devices ADT7473", sizeof("Analog Devices ADT7473")); return 1; } else if (chip_id == 0x75 && dev->SlaveAddr / 2 == 0x2e) { dev->chip_id = ADT7473; dev->chip_name = (char*)STRDUP("Analog Devices ADT7475", sizeof("Analog Devices ADT7475")); return 1; } else if (chip_id == 0x76) { dev->chip_id = ADT7473; dev->chip_name = (char*)STRDUP("Analog Devices ADT7476", sizeof("Analog Devices ADT7476")); return 1; } else if ((dev_id & 0xfc) == 0x6c) { dev->chip_id = ADT7473; dev->chip_name = (char*)STRDUP("Analog Devices ADT7490", sizeof("Analog Devices ADT7490")); return 1; } return 0; }
/* * VT1625/VT1625S sense connected TV outputs. * * The lower six bits of the return byte stand for each of the six DACs: * - bit 0: DACf (Cb) * - bit 1: DACe (Cr) * - bit 2: DACd (Y) * - bit 3: DACc (Composite) * - bit 4: DACb (S-Video C) * - bit 5: DACa (S-Video Y) * * If a bit is 0 it means a cable is connected. Note the VT1625S only has * four DACs, corresponding to bit 0-3 above. */ static CARD8 VT1625DACSenseI2C(I2CDevPtr pDev) { CARD8 power, status, overflow, dacPresent; xf86I2CReadByte(pDev, 0x0E, &power); // save power state // VT1625S will always report 0 for bits 4 and 5 of the status register as // it only has four DACs instead of six. This will result in a false // positive for the S-Video cable. It will also do this on the power // register, which is abused to check which DACs are actually present. xf86I2CWriteByte(pDev, 0x0E, 0xFF); xf86I2CReadByte(pDev, 0x0E, &dacPresent); xf86I2CWriteByte(pDev, 0x0E, 0x00); // power on DACs/circuits xf86I2CReadByte(pDev, 0x1C, &overflow); // save overflow reg // (DAC sense bit should be off) xf86I2CWriteByte(pDev, 0x1C, 0x80); // enable DAC sense bit xf86I2CWriteByte(pDev, 0x1C, overflow); // disable DAC sense bit xf86I2CReadByte(pDev, 0x0F, &status); // read connection status xf86I2CWriteByte(pDev, 0x0E, power); // restore power state status |= ~dacPresent; return (status & 0x3F); }
/* This function should return the chip type .. */ int lm99_detect(I2CDevPtr dev) { I2CByte man_id, chip_id; xf86I2CReadByte (dev, LM99_REG_MAN_ID, &man_id); xf86I2CReadByte (dev, LM99_REG_CHIP_ID, &chip_id); switch(man_id) { /* National Semiconductor LM99; needs offset? */ case NATSEM_MAN_ID: dev->chip_id = LM99; dev->chip_name = (char*)STRDUP("National Semiconductor LM99", sizeof("National Semiconductor LM99")); break; /* Unknown vendor; this chip was used in a FX5700Go laptop and looks similar to the MAx6659 */ case 0x47: /* Maxim; likely a 655x model */ case MAXIM_MAN_ID: dev->chip_id = MAX6559; dev->chip_name = (char*)STRDUP("Maxim MAX6659", sizeof("Maxim MAX6659")); break; default: return 0; } return 1; }
int adt7473_get_board_temp(nouveau_device *device) { I2CByte temp; I2CByte cfg; xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_LOCAL_TEMP, &temp); /* Check if the sensor uses 2-complement or offset-64 mode */ xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_CFG5, &cfg); if(cfg & 0x1) return (int)((char)temp); else return temp - 64; }
/* * For VT1621 the same as for VT1622/VT1622A/VT1623, but result is different. * Still needs testing on VT1621, of course. */ static CARD8 VT162xDACSenseI2C(I2CDevPtr pDev) { CARD8 save, sense; xf86I2CReadByte(pDev, 0x0E, &save); xf86I2CWriteByte(pDev, 0x0E, 0x00); xf86I2CWriteByte(pDev, 0x0E, 0x80); xf86I2CWriteByte(pDev, 0x0E, 0x00); xf86I2CReadByte(pDev, 0x0F, &sense); xf86I2CWriteByte(pDev, 0x0E, save); return (sense & 0x0F); }
int lm99_get_gpu_temp(I2CDevPtr dev) { I2CByte temp; xf86I2CReadByte(dev, LM99_REG_REMOTE_TEMP, &temp); /* Cards with lm99 chips need an offset of 16C according to the datasheets. */ if(dev->chip_id == LM99) { temp += 16; } /* The temperature needs to be corrected using an offset which is stored in the bios. / If no bios has been parsed we fall back to a default value. */ if(nv_card->bios) { temp += nv_card->bios->sensor_cfg.temp_correction; } else { /* An extra offset of 10C seems to be needed on Geforce6800 cards to match nvidia-settings. / Last but not least Geforce6600GT boards containing an LM99 sensor seem to need a +5C offset. */ if(dev->arch == NV43) temp += 5; else if(dev->arch & NV4X) temp += 10; } return temp; }
int adt7473_get_fanspeed_pwm(nouveau_device *device) { I2CByte value; xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_PWM1_DUTYCYCLE, &value); return ((float)value*100/255); }
int lm99_get_gpu_temp(nouveau_device *device) { I2CByte temp; xf86I2CReadByte(device->nvclock_i2c_sensor, LM99_REG_REMOTE_TEMP, &temp); /* Cards with lm99 chips need an offset of 16C according to the datasheets. */ if(device->nvclock_i2c_sensor->chip_id == LM99) { temp += 16; } /* The temperature needs to be corrected using an offset which is stored in the bios. / If no bios has been parsed we fall back to a default value. */ if(device->bios.data) { temp += device->sensor_constants.offset_constant; //nv_card->bios->sensor_cfg.temp_correction; } else { /* An extra offset of 10C seems to be needed on Geforce6800 cards to match nvidia-settings. / Last but not least Geforce6600GT boards containing an LM99 sensor seem to need a +5C offset. */ if(device->chipset == 0x43) temp += 5; else if(device->card_type == NV_40) temp += 10; } return temp; }
int adt7473_set_fanspeed_pwm(I2CDevPtr dev, float speed) { I2CByte value = (int)speed * 255/100; I2CByte cfg, max_dutycycle; xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); cfg |= 0xe0; /* Put PWM1 in manual mode; this disables automatic control */ xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); /* If the MAX dutycycle is lower than 0xff (100%), set it to 0xff */ xf86I2CReadByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, &max_dutycycle); if(max_dutycycle < 0xff) xf86I2CWriteByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, 0xff); xf86I2CWriteByte(dev, ADT7473_REG_PWM1_DUTYCYCLE, value); return 1; }
int adt7473_get_fanspeed_mode(I2CDevPtr dev) { I2CByte cfg; xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); if(cfg & (0x6 << 5)) return 0; /* auto */ if(cfg & (0x7 << 5)) return 1; /* manual */ return -1; /* something went wrong */ }
int adt7473_get_fanspeed_rpm(nouveau_device *device) { I2CByte count_lb, count_hb; int count; xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_TACH1_LB, &count_lb); xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_TACH1_HB, &count_hb); count = (count_hb << 8) | count_lb; /* GT200 boards seem to use two phases instead of a single, the fan speed is twice as high */ if((device->chipset & 0x1f0) >= 0xA0) count *= 2; /* GF100 boards seem to use four phases... */ if(device->card_type == NV_C0) count *= 4; /* RPM = 60*90k pulses / (number of counts that fit in a pulse) */ return 90000*60/count; }
int adt7473_get_gpu_temp(nouveau_device *device) { I2CByte temp; I2CByte cfg; int offset = 0; /* The temperature needs to be corrected using an offset which is stored in the bios. / If no bios has been parsed we fall back to a default value. */ if(device->bios.data) { offset = device->sensor_constants.offset_constant;//nv_card->bios->sensor_cfg.temp_correction; } else { /* We add a 10C offset to the temperature though this isn't conform / the ADT7473 datasheet. The reason we add this is to show a temperature / similar to the internal gpu sensor. Right now the board and gpu / temperature as reported by the sensor are about the same (there's / a difference between the two or 3-4C). Most likely the internal gpu / temperature is a bit higher and assuming the temperature as reported / by the internal sensor is correct adding a 10C offset is a good solution. / Add an offset of 8C for 8*00/GTX2*0 cards but it doesn't seem 100% correct though. / It could be that +7C is more correct for 8800GT cards. */ if(device->card_type == NV_40) offset = 10; else if(device->card_type == NV_50) offset = 8; } xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_REMOTE_TEMP, &temp); /* Check if the sensor uses 2-complement or offset-64 mode */ xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_CFG5, &cfg); if(cfg & 0x1) return (int)((char)temp + offset); else return temp - 64 + offset; }
static void VT162xSave(ScrnInfoPtr pScrn) { int i; VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT162xSave\n")); for (i = 0; i < pBIOSInfo->TVNumRegs; i++) xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &(pBIOSInfo->TVRegs[i])); }
void adt7473_set_fanspeed_mode(I2CDevPtr dev, int mode) { I2CByte cfg; xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); /* Clear the pwm1 config bits */ cfg&=~(0xF << 5); if(mode==1) cfg|=0x7 << 5; /* manual */ else cfg|=0x6 << 5; /* auto */ xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); }
static void VT1621ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode) { VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo; struct VT1621TableRec Table = VT1621Table[VT1621ModeIndex(pScrn, mode)]; CARD8 i; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1621ModeI2C\n")); for (i = 0; i < 0x16; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]); VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier); /* Skip reserved (1A) and version ID (1B). */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV[0x1C]); /* Skip software reset (1D). */ for (i = 0x1E; i < 0x24; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV[i]); /* Write some zeroes? */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x24, 0x00); for (i = 0; i < 0x08; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, 0x00); if (pBIOSInfo->TVOutput == TVOUTPUT_COMPOSITE) for (i = 0; i < 0x10; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVC[i]); else for (i = 0; i < 0x10; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x52 + i, Table.TVS[i]); /* Turn on all Composite and S-Video output. */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00); if (pBIOSInfo->TVDotCrawl) { if (Table.DotCrawlSubCarrier) { xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &i); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, i | 0x08); VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier); } else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently " "support DotCrawl suppression.\n"); } }
static void VT162xPrintRegs(ScrnInfoPtr pScrn) { VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo; CARD8 i, buf; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing registers for %s\n", pBIOSInfo->TVI2CDev->DevName); for (i = 0; i < pBIOSInfo->TVNumRegs; i++) { xf86I2CReadByte(pBIOSInfo->TVI2CDev, i, &buf); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV%02X: 0x%02X\n", i, buf); } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of TV registers.\n"); }
/* * Also suited for VT1622A, VT1623, VT1625. */ static void VT1622ModeI2C(ScrnInfoPtr pScrn, DisplayModePtr mode) { VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo; struct VT162XTableRec Table; CARD8 save, i; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VT1622ModeI2C\n")); if (pBIOSInfo->TVEncoder == VIA_VT1622) Table = VT1622Table[VT1622ModeIndex(pScrn, mode)]; else if (pBIOSInfo->TVEncoder == VIA_VT1625) Table = VT1625Table[VT1622ModeIndex(pScrn, mode)]; else /* VT1622A/VT1623 */ Table = VT1623Table[VT1622ModeIndex(pScrn, mode)]; /* TV reset. */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x00); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x80); for (i = 0; i < 0x16; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]); VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.SubCarrier); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1A, Table.TV1[0x1A]); /* Skip version ID. */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1C, Table.TV1[0x1C]); /* Skip software reset. */ for (i = 0x1E; i < 0x30; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, i, Table.TV1[i]); for (i = 0; i < 0x1B; i++) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A + i, Table.TV2[i]); /* Turn on all Composite and S-Video output. */ xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x0E, 0x00); if (pBIOSInfo->TVDotCrawl) { if (Table.DotCrawlSubCarrier) { xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x11, &save); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x11, save | 0x08); VT162xSetSubCarrier(pBIOSInfo->TVI2CDev, Table.DotCrawlSubCarrier); } else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "This mode does not currently " "support DotCrawl suppression.\n"); } if (pBIOSInfo->TVOutput == TVOUTPUT_RGB) { xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x2A); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.RGB[0]); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.RGB[1]); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.RGB[2]); if (Table.RGB[3]) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x27, Table.RGB[3]); if (Table.RGB[4]) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2B, Table.RGB[4]); if (Table.RGB[5]) xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x2C, Table.RGB[5]); if (pBIOSInfo->TVEncoder == VIA_VT1625) { if (pBIOSInfo->TVType < TVTYPE_480P) { xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00); } else { xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x12); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4A, 0x85); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4B, 0x0A); } } } else if (pBIOSInfo->TVOutput == TVOUTPUT_YCBCR) { xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x02, 0x03); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x65, Table.YCbCr[0]); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x66, Table.YCbCr[1]); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x67, Table.YCbCr[2]); if (pBIOSInfo->TVEncoder == VIA_VT1625) { if (pBIOSInfo->TVType < TVTYPE_480P) { xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x23, 0x7E); xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x4E, 0x00); } } } /* Configure flicker filter. */ xf86I2CReadByte(pBIOSInfo->TVI2CDev, 0x03, &save); save &= 0xFC; if (pBIOSInfo->TVDeflicker == 1) save |= 0x01; else if (pBIOSInfo->TVDeflicker == 2) save |= 0x02; xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x03, save); }
I2CDevPtr ViaVT162xDetect(ScrnInfoPtr pScrn, I2CBusPtr pBus, CARD8 Address) { VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo; I2CDevPtr pDev = xf86CreateI2CDevRec(); CARD8 buf; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVT162xDetect\n")); pDev->DevName = "VT162x"; pDev->SlaveAddr = Address; pDev->pI2CBus = pBus; if (!xf86I2CDevInit(pDev)) { xf86DestroyI2CDevRec(pDev, TRUE); return NULL; } if (!xf86I2CReadByte(pDev, 0x1B, &buf)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to read from %s Slave %d.\n", pBus->BusName, Address); xf86DestroyI2CDevRec(pDev, TRUE); return NULL; } switch (buf) { case 0x02: xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected VIA Technologies VT1621 TV Encoder\n"); pBIOSInfo->TVEncoder = VIA_VT1621; pDev->DevName = "VT1621"; break; case 0x03: xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected VIA Technologies VT1622 TV Encoder\n"); pBIOSInfo->TVEncoder = VIA_VT1622; pDev->DevName = "VT1622"; break; case 0x10: xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected VIA Technologies VT1622A/VT1623 TV Encoder\n"); pBIOSInfo->TVEncoder = VIA_VT1623; pDev->DevName = "VT1623"; break; case 0x50: xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected VIA Technologies VT1625 TV Encoder\n"); pBIOSInfo->TVEncoder = VIA_VT1625; pDev->DevName = "VT1625"; break; default: pBIOSInfo->TVEncoder = VIA_NONETV; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown TV Encoder found at %s %X.\n", pBus->BusName, Address); xf86DestroyI2CDevRec(pDev, TRUE); pDev = NULL; break; } return pDev; }
/* This function should return the chip type .. */ int lm99_detect(I2CDevPtr dev) { I2CByte man_id, chip_id, config1, config2, convrate, address = dev->SlaveAddr / 2; const char *name = NULL; if (!xf86I2CReadByte(dev, LM99_REG_MAN_ID, &man_id) || !xf86I2CReadByte(dev, LM99_REG_CHIP_ID, &chip_id) || !xf86I2CReadByte(dev, LM90_REG_R_CONFIG1, &config1) || !xf86I2CReadByte(dev, LM90_REG_R_CONVRATE, &convrate)) return 0; if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) { if (!xf86I2CReadByte(dev, LM90_REG_R_CONVRATE, &config2)) return 0; } else config2 = 0; if ((address == 0x4C || address == 0x4D) && man_id == 0x01) { /* National Semiconductor */ if ((config1 & 0x2A) == 0x00 && (config2 & 0xF8) == 0x00 && convrate <= 0x09) { if (address == 0x4C & (chip_id & 0xF0) == 0x20) { /* LM90 */ name = "National Semiconductor LM90"; dev->chip_id = LM99; } else if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ name = "National Semiconductor :M99"; dev->chip_id = LM99; } else if (address == 0x4C && (chip_id & 0xF0) == 0x10) { /* LM86 */ name = "National Semiconductor LM86"; dev->chip_id = LM99; } } } else if ((address == 0x4C || address == 0x4D) && man_id == 0x41) { /* Analog Devices */ if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ && (config1 & 0x3F) == 0x00 && convrate <= 0x0A) { name = "Analog Devices ADM1032"; dev->chip_id = LM99; /* * The ADM1032 supports PEC, but only if combined * transactions are not used. */ // if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) // info->flags |= I2C_CLIENT_PEC; } else if (chip_id == 0x51 /* ADT7461 */ && (config1 & 0x1B) == 0x00 && convrate <= 0x0A) { name = "Analog Devices ADT7461"; dev->chip_id = LM99; } else if (chip_id == 0x57 /* ADT7461A, NCT1008 */ && (config1 & 0x1B) == 0x00 && convrate <= 0x0A) { name = "Analog Devices ADT7461A"; dev->chip_id = MAX6559; } } else if (man_id == 0x4D) { /* Maxim */ I2CByte emerg, emerg2, status2; /* * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG * exists, both readings will reflect the same value. Otherwise, * the readings will be different. */ if (!xf86I2CReadByte(dev, MAX6659_REG_R_REMOTE_EMERG, &emerg) || !xf86I2CReadByte(dev, LM99_REG_MAN_ID, &man_id) || !xf86I2CReadByte(dev, MAX6659_REG_R_REMOTE_EMERG, &emerg2) || !xf86I2CReadByte (dev, MAX6696_REG_R_STATUS2, &status2)) return 0; /* * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id * register. Reading from that address will return the last * read value, which in our case is those of the man_id * register. Likewise, the config1 register seems to lack a * low nibble, so the value will be those of the previous * read, so in our case those of the man_id register. * MAX6659 has a third set of upper temperature limit registers. * Those registers also return values on MAX6657 and MAX6658, * thus the only way to detect MAX6659 is by its address. * For this reason it will be mis-detected as MAX6657 if its * address is 0x4C. */ if (chip_id == man_id && (address == 0x4C || address == 0x4D || address == 0x4E) && (config1 & 0x1F) == (man_id & 0x0F) && convrate <= 0x09) { if (address == 0x4C) name = "Maxim MAX6657"; else name = "Maxim MAX6659"; dev->chip_id = MAX6559; } /* * Even though MAX6695 and MAX6696 do not have a chip ID * register, reading it returns 0x01. Bit 4 of the config1 * register is unused and should return zero when read. Bit 0 of * the status2 register is unused and should return zero when * read. * * MAX6695 and MAX6696 have an additional set of temperature * limit registers. We can detect those chips by checking if * one of those registers exists. */ else if (chip_id == 0x01 && (config1 & 0x10) == 0x00 && (status2 & 0x01) == 0x00 && emerg == emerg2 && convrate <= 0x07) { name = "Maxim MAX6696"; dev->chip_id = MAX6559; } /* * The chip_id register of the MAX6680 and MAX6681 holds the * revision of the chip. The lowest bit of the config1 register * is unused and should return zero when read, so should the * second to last bit of config1 (software reset). */ else if (chip_id == 0x01 && (config1 & 0x03) == 0x00 && convrate <= 0x07) { name = "Maxim MAX6680"; dev->chip_id = LM99; } /* * The chip_id register of the MAX6646/6647/6649 holds the * revision of the chip. The lowest 6 bits of the config1 * register are unused and should return zero when read. */ else if (chip_id == 0x59 && (config1 & 0x3f) == 0x00 && convrate <= 0x07) { name = "Maxim MAX6646"; dev->chip_id = MAX6559; } } else if (address == 0x4C && man_id == 0x5C) { /* Winbond/Nuvoton */ if ((config1 & 0x2A) == 0x00 && (config2 & 0xF8) == 0x00) { if (chip_id == 0x01 /* W83L771W/G */ && convrate <= 0x09) { name = "Winbond/Nuvoton W83l771"; dev->chip_id = MAX6559; } else if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ && convrate <= 0x08) { name = "Winbond/Nuvoton W83l771"; dev->chip_id = LM99; } } } else if (address >= 0x48 && address <= 0x4F && man_id == 0xA1) { /* NXP Semiconductor/Philips */ if (chip_id == 0x00 && (config1 & 0x2A) == 0x00 && (config2 & 0xFE) == 0x00 && convrate <= 0x09) { name = "NXP Semiconductor/Philips SA56004"; dev->chip_id = LM99; } } else if ((address == 0x4C || address == 0x4D) && man_id == 0x47) { /* GMT */ if (chip_id == 0x01 /* G781 */ && (config1 & 0x3F) == 0x00 && convrate <= 0x08) { name = "GMT G781"; dev->chip_id = LM99; } } if (!name) /* identification failed */ return 0; dev->chip_name = STRDUP(name, sizeof(name)); return 1; }
int lm99_get_board_temp(I2CDevPtr dev) { I2CByte temp; xf86I2CReadByte(dev, LM99_REG_LOCAL_TEMP, &temp); return temp; }
int lm99_get_board_temp(nouveau_device *device) { I2CByte temp; xf86I2CReadByte(device->nvclock_i2c_sensor, LM99_REG_LOCAL_TEMP, &temp); return temp; }