1
0
Fork 0

hwmon: (f75375s) Add support for F75387SG/RG

Fintek F75387SG/RG is mostly compatible to F75373/F75375. Add support for it
to the F75375S driver.

Fan support for F75387SG/RG has been implemented but not tested.

Cc: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Bjoern Gerhart <oss@extracloud.de>
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
hifive-unleashed-5.1
Björn Gerhart 2011-12-13 13:19:58 -05:00 committed by Guenter Roeck
parent 5cd3222a9f
commit f58c44e698
2 changed files with 130 additions and 49 deletions

View File

@ -367,11 +367,11 @@ config SENSORS_F71882FG
will be called f71882fg. will be called f71882fg.
config SENSORS_F75375S config SENSORS_F75375S
tristate "Fintek F75375S/SP and F75373" tristate "Fintek F75375S/SP, F75373 and F75387"
depends on I2C depends on I2C
help help
If you say yes here you get support for hardware monitoring If you say yes here you get support for hardware monitoring
features of the Fintek F75375S/SP and F75373 features of the Fintek F75375S/SP, F75373 and F75387
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called f75375s. will be called f75375s.

View File

@ -1,6 +1,6 @@
/* /*
* f75375s.c - driver for the Fintek F75375/SP and F75373 * f75375s.c - driver for the Fintek F75375/SP, F75373 and
* hardware monitoring features * F75387SG/RG hardware monitoring features
* Copyright (C) 2006-2007 Riku Voipio * Copyright (C) 2006-2007 Riku Voipio
* *
* Datasheets available at: * Datasheets available at:
@ -11,6 +11,9 @@
* f75373: * f75373:
* http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf
* *
* f75387:
* http://www.fintek.com.tw/files/productfiles/F75387_V027P.pdf
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -40,7 +43,7 @@
/* Addresses to scan */ /* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
enum chips { f75373, f75375 }; enum chips { f75373, f75375, f75387 };
/* Fintek F75375 registers */ /* Fintek F75375 registers */
#define F75375_REG_CONFIG0 0x0 #define F75375_REG_CONFIG0 0x0
@ -59,6 +62,7 @@ enum chips { f75373, f75375 };
#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2) #define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2)
#define F75375_REG_TEMP(nr) (0x14 + (nr)) #define F75375_REG_TEMP(nr) (0x14 + (nr))
#define F75387_REG_TEMP11_LSB(nr) (0x1a + (nr))
#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2) #define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2)
#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2) #define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2)
@ -78,8 +82,11 @@ enum chips { f75373, f75375 };
#define F75375_REG_PWM1_DROP_DUTY 0x6B #define F75375_REG_PWM1_DROP_DUTY 0x6B
#define F75375_REG_PWM2_DROP_DUTY 0x6C #define F75375_REG_PWM2_DROP_DUTY 0x6C
#define FAN_CTRL_LINEAR(nr) (4 + nr) #define F75375_FAN_CTRL_LINEAR(nr) (4 + nr)
#define F75387_FAN_CTRL_LINEAR(nr) (1 + ((nr) * 4))
#define FAN_CTRL_MODE(nr) (4 + ((nr) * 2)) #define FAN_CTRL_MODE(nr) (4 + ((nr) * 2))
#define F75387_FAN_DUTY_MODE(nr) (2 + ((nr) * 4))
#define F75387_FAN_MANU_MODE(nr) ((nr) * 4)
/* /*
* Data structures and manipulation thereof * Data structures and manipulation thereof
@ -108,7 +115,12 @@ struct f75375_data {
u8 pwm[2]; u8 pwm[2];
u8 pwm_mode[2]; u8 pwm_mode[2];
u8 pwm_enable[2]; u8 pwm_enable[2];
s8 temp[2]; /*
* f75387: For remote temperature reading, it uses signed 11-bit
* values with LSB = 0.125 degree Celsius, left-justified in 16-bit
* registers. For original 8-bit temp readings, the LSB just is 0.
*/
s16 temp11[2];
s8 temp_high[2]; s8 temp_high[2];
s8 temp_max_hyst[2]; s8 temp_max_hyst[2];
}; };
@ -122,6 +134,7 @@ static int f75375_remove(struct i2c_client *client);
static const struct i2c_device_id f75375_id[] = { static const struct i2c_device_id f75375_id[] = {
{ "f75373", f75373 }, { "f75373", f75373 },
{ "f75375", f75375 }, { "f75375", f75375 },
{ "f75387", f75387 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, f75375_id); MODULE_DEVICE_TABLE(i2c, f75375_id);
@ -205,8 +218,14 @@ static struct f75375_data *f75375_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + 2 * HZ) if (time_after(jiffies, data->last_updated + 2 * HZ)
|| !data->valid) { || !data->valid) {
for (nr = 0; nr < 2; nr++) { for (nr = 0; nr < 2; nr++) {
data->temp[nr] = /* assign MSB, therefore shift it by 8 bits */
f75375_read8(client, F75375_REG_TEMP(nr)); data->temp11[nr] =
f75375_read8(client, F75375_REG_TEMP(nr)) << 8;
if (data->kind == f75387)
/* merge F75387's temperature LSB (11-bit) */
data->temp11[nr] |=
f75375_read8(client,
F75387_REG_TEMP11_LSB(nr));
data->fan[nr] = data->fan[nr] =
f75375_read16(client, F75375_REG_FAN(nr)); f75375_read16(client, F75375_REG_FAN(nr));
} }
@ -313,24 +332,50 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
return -EINVAL; return -EINVAL;
fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
fanmode &= ~(3 << FAN_CTRL_MODE(nr)); if (data->kind == f75387) {
/* clear each fanX_mode bit before setting them properly */
switch (val) { fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr));
case 0: /* Full speed */ fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr));
fanmode |= (3 << FAN_CTRL_MODE(nr)); switch (val) {
data->pwm[nr] = 255; case 0: /* full speed */
f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
data->pwm[nr]); fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
break; data->pwm[nr] = 255;
case 1: /* PWM */ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
fanmode |= (3 << FAN_CTRL_MODE(nr)); data->pwm[nr]);
break; break;
case 2: /* AUTOMATIC*/ case 1: /* PWM */
fanmode |= (2 << FAN_CTRL_MODE(nr)); fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
break; fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
case 3: /* fan speed */ break;
break; case 2: /* AUTOMATIC*/
fanmode |= (1 << F75387_FAN_DUTY_MODE(nr));
break;
case 3: /* fan speed */
fanmode |= (1 << F75387_FAN_MANU_MODE(nr));
break;
}
} else {
/* clear each fanX_mode bit before setting them properly */
fanmode &= ~(3 << FAN_CTRL_MODE(nr));
switch (val) {
case 0: /* full speed */
fanmode |= (3 << FAN_CTRL_MODE(nr));
data->pwm[nr] = 255;
f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
data->pwm[nr]);
break;
case 1: /* PWM */
fanmode |= (3 << FAN_CTRL_MODE(nr));
break;
case 2: /* AUTOMATIC*/
fanmode |= (2 << FAN_CTRL_MODE(nr));
break;
case 3: /* fan speed */
break;
}
} }
f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
data->pwm_enable[nr] = val; data->pwm_enable[nr] = val;
return 0; return 0;
@ -364,6 +409,7 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
unsigned long val; unsigned long val;
int err; int err;
u8 conf; u8 conf;
char reg, ctrl;
err = kstrtoul(buf, 10, &val); err = kstrtoul(buf, 10, &val);
if (err < 0) if (err < 0)
@ -376,14 +422,23 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
if (data->kind == f75373 && val == 0) if (data->kind == f75373 && val == 0)
return -EINVAL; return -EINVAL;
/* take care for different registers */
if (data->kind == f75387) {
reg = F75375_REG_FAN_TIMER;
ctrl = F75387_FAN_CTRL_LINEAR(nr);
} else {
reg = F75375_REG_CONFIG1;
ctrl = F75375_FAN_CTRL_LINEAR(nr);
}
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
conf = f75375_read8(client, F75375_REG_CONFIG1); conf = f75375_read8(client, reg);
conf &= ~(1 << FAN_CTRL_LINEAR(nr)); conf &= ~(1 << ctrl);
if (val == 0) if (val == 0)
conf |= (1 << FAN_CTRL_LINEAR(nr)) ; conf |= (1 << ctrl);
f75375_write8(client, F75375_REG_CONFIG1, conf); f75375_write8(client, reg, conf);
data->pwm_mode[nr] = val; data->pwm_mode[nr] = val;
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
@ -475,13 +530,14 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
} }
#define TEMP_FROM_REG(val) ((val) * 1000) #define TEMP_FROM_REG(val) ((val) * 1000)
#define TEMP_TO_REG(val) ((val) / 1000) #define TEMP_TO_REG(val) ((val) / 1000)
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
static ssize_t show_temp(struct device *dev, struct device_attribute *attr, static ssize_t show_temp11(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
int nr = to_sensor_dev_attr(attr)->index; int nr = to_sensor_dev_attr(attr)->index;
struct f75375_data *data = f75375_update_device(dev); struct f75375_data *data = f75375_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[nr]));
} }
static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
@ -577,12 +633,12 @@ static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
show_in_max, set_in_max, 3); show_in_max, set_in_max, 3);
static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR, static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
show_in_min, set_in_min, 3); show_in_min, set_in_min, 3);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
show_temp_max_hyst, set_temp_max_hyst, 0); show_temp_max_hyst, set_temp_max_hyst, 0);
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR, static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
show_temp_max, set_temp_max, 0); show_temp_max, set_temp_max, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
show_temp_max_hyst, set_temp_max_hyst, 1); show_temp_max_hyst, set_temp_max_hyst, 1);
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
@ -664,18 +720,38 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
conf = f75375_read8(client, F75375_REG_CONFIG1); conf = f75375_read8(client, F75375_REG_CONFIG1);
mode = f75375_read8(client, F75375_REG_FAN_TIMER); mode = f75375_read8(client, F75375_REG_FAN_TIMER);
for (nr = 0; nr < 2; nr++) { for (nr = 0; nr < 2; nr++) {
if (!(conf & (1 << FAN_CTRL_LINEAR(nr)))) if (data->kind == f75387) {
data->pwm_mode[nr] = 1; bool manu, duty;
switch ((mode >> FAN_CTRL_MODE(nr)) & 3) {
case 0: /* speed */ if (!(conf & (1 << F75387_FAN_CTRL_LINEAR(nr))))
data->pwm_enable[nr] = 3; data->pwm_mode[nr] = 1;
break;
case 1: /* automatic */ manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1);
data->pwm_enable[nr] = 2; duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1);
break; if (manu && duty)
default: /* manual */ /* speed */
data->pwm_enable[nr] = 1; data->pwm_enable[nr] = 3;
break; else if (!manu && duty)
/* automatic */
data->pwm_enable[nr] = 2;
else
/* manual */
data->pwm_enable[nr] = 1;
} else {
if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr))))
data->pwm_mode[nr] = 1;
switch ((mode >> FAN_CTRL_MODE(nr)) & 3) {
case 0: /* speed */
data->pwm_enable[nr] = 3;
break;
case 1: /* automatic */
data->pwm_enable[nr] = 2;
break;
default: /* manual */
data->pwm_enable[nr] = 1;
break;
}
} }
} }
return; return;
@ -763,10 +839,15 @@ static int f75375_detect(struct i2c_client *client,
vendid = f75375_read16(client, F75375_REG_VENDOR); vendid = f75375_read16(client, F75375_REG_VENDOR);
chipid = f75375_read16(client, F75375_CHIP_ID); chipid = f75375_read16(client, F75375_CHIP_ID);
if (chipid == 0x0306 && vendid == 0x1934) if (vendid != 0x1934)
return -ENODEV;
if (chipid == 0x0306)
name = "f75375"; name = "f75375";
else if (chipid == 0x0204 && vendid == 0x1934) else if (chipid == 0x0204)
name = "f75373"; name = "f75373";
else if (chipid == 0x0410)
name = "f75387";
else else
return -ENODEV; return -ENODEV;
@ -789,7 +870,7 @@ static void __exit sensors_f75375_exit(void)
MODULE_AUTHOR("Riku Voipio"); MODULE_AUTHOR("Riku Voipio");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver"); MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver");
module_init(sensors_f75375_init); module_init(sensors_f75375_init);
module_exit(sensors_f75375_exit); module_exit(sensors_f75375_exit);