/* NVClock 0.8 - Linux overclocker for NVIDIA cards
*
* site: http://nvclock.sourceforge.net
*
* Copyright(C) 2001-2005 Roderick Colenbrander
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* ADT7473 hardware monitoring
*/
#include <string.h>
#include "i2c.h"
#include "nvclock.h"
/* various defines for register offsets and such are needed */
#define ADT7473_REG_LOCAL_TEMP 0x26
#define ADT7473_REG_LOCAL_TEMP_OFFSET 0x70
#define ADT7473_REG_REMOTE_TEMP 0x25
#define ADT7473_REG_REMOTE_TEMP_OFFSET 0x71
#define ADT7473_REG_PWM1_CFG 0x5c
#define ADT7473_REG_PWM1_DUTYCYCLE 0x30
#define ADT7473_REG_PWM1_MAX_DUTYCYCLE 0x38
#define ADT7473_REG_PWM1_MIN_DUTYCYCLE 0x64
#define ADT7473_REG_TACH1_LB 0x28
#define ADT7473_REG_TACH1_HB 0x29
#define ADT7473_REG_CFG5 0x7c
#define ADT7473_REG_MAN_ID 0x3e
#define AD_MAN_ID 0x41
#define ADT7473_REG_CHIP_ID 0x3d
#define ADT7473_CHIP_ID 0x73
/* This function should return the chip type .. */
int adt7473_detect(I2CDevPtr dev)
{
I2CByte man_id, chip_id;
xf86I2CReadByte(dev, ADT7473_REG_MAN_ID, &man_id);
xf86I2CReadByte(dev, ADT7473_REG_CHIP_ID, &chip_id);
if((man_id == AD_MAN_ID) && (chip_id == ADT7473_CHIP_ID))
{
dev->chip_id = ADT7473;
dev->chip_name = (char*)strdup("Analog Devices ADT7473");
return 1;
}
return 0;
}
int adt7473_get_board_temp(I2CDevPtr dev)
{
I2CByte temp;
I2CByte cfg;
xf86I2CReadByte(dev, ADT7473_REG_LOCAL_TEMP, &temp);
/* Check if the sensor uses 2-complement or offset-64 mode */
xf86I2CReadByte(dev, ADT7473_REG_CFG5, &cfg);
if(cfg & 0x1)
return (int)((char)temp);
else
return temp - 64;
}
int adt7473_get_gpu_temp(I2CDevPtr dev)
{
I2CByte temp;
I2CByte cfg;
xf86I2CReadByte(dev, ADT7473_REG_REMOTE_TEMP, &temp);
/* Check if the sensor uses 2-complement or offset-64 mode */
/* 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.
/ (The offset seems to be the same independant of the temperature which)
*/
xf86I2CReadByte(dev, ADT7473_REG_CFG5, &cfg);
if(cfg & 0x1)
return (int)((char)temp+10);
else
return temp - 64 + 10;
}
int adt7473_get_fanspeed_rpm(I2CDevPtr dev)
{
I2CByte count_lb, count_hb;
int count;
xf86I2CReadByte(dev, ADT7473_REG_TACH1_LB, &count_lb);
xf86I2CReadByte(dev, ADT7473_REG_TACH1_HB, &count_hb);
count = (count_hb << 8) | count_lb;
/* RPM = 60*90k pulses / (number of counts that fit in a pulse) */
return 90000*60/count;
}
float adt7473_get_fanspeed_pwm(I2CDevPtr dev)
{
I2CByte value;
xf86I2CReadByte(dev, ADT7473_REG_PWM1_DUTYCYCLE, &value);
return (float)value*100/255;
}
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 */
}
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);
}
syntax highlighted by Code2HTML, v. 0.9.1