#include <linux/delay.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+ 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
+};
static int reset;
#define W83795_REG_I2C_ADDR 0xfc
#define W83795_REG_CONFIG 0x01
#define W83795_REG_CONFIG_CONFIG48 0x04
+#define W83795_REG_CONFIG_START 0x01
/* Multi-Function Pin Ctrl Registers */
#define W83795_REG_VOLT_CTRL1 0x02
#define TEMP_CTRL_SHIFT 4
#define TEMP_CTRL_HASIN_SHIFT 5
/* temp mode may effect VSEN17-12 (in20-15) */
-static u16 W83795_REG_TEMP_CTRL[][6] = {
+static const u16 W83795_REG_TEMP_CTRL[][6] = {
/* Disable, TD, VSEN, TR, register shift value, has_in shift num */
{0x00, 0x01, 0x02, 0x03, 0, 17}, /* TR1 */
{0x00, 0x04, 0x08, 0x0C, 2, 18}, /* TR2 */
#define TEMP_WARN_HYST 4
/* only crit and crit_hyst affect real-time alarm status
* current crit crit_hyst warn warn_hyst */
-static u16 W83795_REG_TEMP[][5] = {
+static const u16 W83795_REG_TEMP[][5] = {
{0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */
{0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */
{0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */
#define W83795_REG_FCMS2 0x208
#define W83795_REG_TFMR(index) (0x202 + (index))
#define W83795_REG_FOMC 0x20F
-#define W83795_REG_FOPFP(index) (0x218 + (index))
#define W83795_REG_TSS(index) (0x209 + (index))
#define PWM_START 1
#define PWM_NONSTOP 2
#define PWM_STOP_TIME 3
-#define PWM_DIV 4
+#define PWM_FREQ 4
#define W83795_REG_PWM(index, nr) \
(((nr) == 0 ? 0x210 : \
(nr) == 1 ? 0x220 : \
(nr) == 2 ? 0x228 : \
(nr) == 3 ? 0x230 : 0x218) + (index))
-#define W83795_REG_FOPFP_DIV(index) \
- (((index) < 8) ? ((index) + 1) : \
- ((index) == 8) ? 12 : \
- (16 << ((index) - 9)))
-
#define W83795_REG_FTSH(index) (0x240 + (index) * 2)
#define W83795_REG_FTSL(index) (0x241 + (index) * 2)
#define W83795_REG_TFTS 0x250
static inline unsigned long fan_from_reg(u16 val)
{
- if ((val >= 0xff0) || (val == 0))
+ if ((val == 0xfff) || (val == 0))
return 0;
return 1350000UL / val;
}
return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max);
}
+static const u16 pwm_freq_cksel0[16] = {
+ 1024, 512, 341, 256, 205, 171, 146, 128,
+ 85, 64, 32, 16, 8, 4, 2, 1
+};
+
+static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin)
+{
+ unsigned long base_clock;
+
+ if (reg & 0x80) {
+ base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+ return base_clock / ((reg & 0x7f) + 1);
+ } else
+ return pwm_freq_cksel0[reg & 0x0f];
+}
+
+static u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
+{
+ unsigned long base_clock;
+ u8 reg0, reg1;
+ unsigned long best0, best1;
+
+ /* Best fit for cksel = 0 */
+ for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) {
+ if (val > (pwm_freq_cksel0[reg0] +
+ pwm_freq_cksel0[reg0 + 1]) / 2)
+ break;
+ }
+ if (val < 375) /* cksel = 1 can't beat this */
+ return reg0;
+ best0 = pwm_freq_cksel0[reg0];
+
+ /* Best fit for cksel = 1 */
+ base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+ reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
+ best1 = base_clock / reg1;
+ reg1 = 0x80 | (reg1 - 1);
+
+ /* Choose the closest one */
+ if (abs(val - best0) > abs(val - best1))
+ return reg1;
+ else
+ return reg0;
+}
enum chip_types {w83795g, w83795adg};
u8 bank;
u32 has_in; /* Enable monitor VIN or not */
+ u8 has_dyn_in; /* Only in2-0 can have this */
u16 in[21][3]; /* Register value, read/high/low */
u8 in_lsb[10][3]; /* LSB Register value, high/low */
u8 has_gain; /* has gain: in17-20 * 8 */
* no config register, only affected by chip
* type */
u8 pwm[8][5]; /* Register value, output, start, non stop, stop
- * time, div */
+ * time, freq */
+ u16 clkin; /* CLKIN frequency in kHz */
u8 pwm_fcms[2]; /* Register value */
u8 pwm_tfmr[6]; /* Register value */
u8 pwm_fomc; /* Register value */
data->in[i][IN_READ] = tmp;
}
+ /* in0-2 can have dynamic limits (W83795G only) */
+ if (data->has_dyn_in) {
+ u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX));
+ u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW));
+
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_dyn_in & (1 << i)))
+ continue;
+ data->in[i][IN_MAX] =
+ w83795_read(client, W83795_REG_IN[i][IN_MAX]);
+ data->in[i][IN_LOW] =
+ w83795_read(client, W83795_REG_IN[i][IN_LOW]);
+ data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03;
+ data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03;
+ }
+ }
+
/* Update fan */
for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
if (!(data->has_fan & (1 << i)))
continue;
data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
data->fan[i] |=
- (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F;
+ (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F;
}
/* Update temperature */
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
- u16 val;
+ unsigned int val;
switch (nr) {
case PWM_STOP_TIME:
val = time_from_reg(data->pwm[index][nr]);
break;
- case PWM_DIV:
- val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f);
+ case PWM_FREQ:
+ val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin);
break;
default:
val = data->pwm[index][nr];
int nr = sensor_attr->nr;
int index = sensor_attr->index;
unsigned long val;
- int i;
if (strict_strtoul(buf, 10, &val) < 0)
return -EINVAL;
case PWM_STOP_TIME:
val = time_to_reg(val);
break;
- case PWM_DIV:
- for (i = 0; i < 16; i++) {
- if (W83795_REG_FOPFP_DIV(i) == val) {
- val = i;
- break;
- }
- }
- if (i >= 16)
- goto err_end;
- val |= w83795_read(client, W83795_REG_PWM(index, nr)) & 0x80;
+ case PWM_FREQ:
+ val = pwm_freq_to_reg(val, data->clkin);
break;
default:
val = SENSORS_LIMIT(val, 0, 0xff);
break;
}
w83795_write(client, W83795_REG_PWM(index, nr), val);
- data->pwm[index][nr] = val & 0xff;
+ data->pwm[index][nr] = val;
mutex_unlock(&data->update_lock);
return count;
-err_end:
- mutex_unlock(&data->update_lock);
- return -EINVAL;
}
static ssize_t
case IN_READ:
/* calculate this value again by sensors as sensors3.conf */
if ((index >= 17) &&
- ((data->has_gain >> (index - 17)) & 1))
+ !((data->has_gain >> (index - 17)) & 1))
val *= 8;
break;
case IN_MAX:
val |= (data->in_lsb[lsb_idx][nr] >>
IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03;
if ((index >= 17) &&
- ((data->has_gain >> (index - 17)) & 1))
+ !((data->has_gain >> (index - 17)) & 1))
val *= 8;
break;
}
val = in_to_reg(index, val);
if ((index >= 17) &&
- ((data->has_gain >> (index - 17)) & 1))
+ !((data->has_gain >> (index - 17)) & 1))
val /= 8;
val = SENSORS_LIMIT(val, 0, 0x3FF);
mutex_lock(&data->update_lock);
#define NOT_USED -1
+/* Don't change the attribute order, _max and _min are accessed by index
+ * somewhere else in the code */
#define SENSOR_ATTR_IN(index) { \
SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
IN_READ, index), \
show_pwm, store_pwm, PWM_START, index - 1), \
SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \
- SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \
- show_pwm, store_pwm, PWM_DIV, index - 1), \
+ SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \
+ show_pwm, store_pwm, PWM_FREQ, index - 1), \
SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \
- show_pwm_enable, store_pwm_enable, NOT_USED, index - 1) }
-
-#define SENSOR_ATTR_FANIN_TARGET(index) \
- SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \
- show_fanin, store_fanin, FANIN_TARGET, index - 1)
+ show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+ SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
+ show_fanin, store_fanin, FANIN_TARGET, index - 1) }
#define SENSOR_ATTR_DTS(index) { \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \
SENSOR_ATTR_IN(20),
};
-static struct sensor_device_attribute_2 w83795_fan[][4] = {
+static const struct sensor_device_attribute_2 w83795_fan[][4] = {
SENSOR_ATTR_FAN(1),
SENSOR_ATTR_FAN(2),
SENSOR_ATTR_FAN(3),
SENSOR_ATTR_FAN(14),
};
-static struct sensor_device_attribute_2 w83795_temp[][29] = {
+static const struct sensor_device_attribute_2 w83795_temp[][29] = {
SENSOR_ATTR_TEMP(1),
SENSOR_ATTR_TEMP(2),
SENSOR_ATTR_TEMP(3),
SENSOR_ATTR_TEMP(6),
};
-static struct sensor_device_attribute_2 w83795_dts[][8] = {
+static const struct sensor_device_attribute_2 w83795_dts[][8] = {
SENSOR_ATTR_DTS(7),
SENSOR_ATTR_DTS(8),
SENSOR_ATTR_DTS(9),
SENSOR_ATTR_DTS(14),
};
-static struct sensor_device_attribute_2 w83795_static[] = {
- SENSOR_ATTR_FANIN_TARGET(1),
- SENSOR_ATTR_FANIN_TARGET(2),
- SENSOR_ATTR_FANIN_TARGET(3),
- SENSOR_ATTR_FANIN_TARGET(4),
- SENSOR_ATTR_FANIN_TARGET(5),
- SENSOR_ATTR_FANIN_TARGET(6),
- SENSOR_ATTR_FANIN_TARGET(7),
- SENSOR_ATTR_FANIN_TARGET(8),
-};
-
-static struct sensor_device_attribute_2 w83795_pwm[][6] = {
+static const struct sensor_device_attribute_2 w83795_pwm[][7] = {
SENSOR_ATTR_PWM(1),
SENSOR_ATTR_PWM(2),
SENSOR_ATTR_PWM(3),
SENSOR_ATTR_PWM(8),
};
-static struct sensor_device_attribute_2 sda_single_files[] = {
+static const struct sensor_device_attribute_2 sda_single_files[] = {
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 46),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
static void w83795_init_client(struct i2c_client *client)
{
+ struct w83795_data *data = i2c_get_clientdata(client);
+ static const u16 clkin[4] = { /* in kHz */
+ 14318, 24000, 33333, 48000
+ };
+ u8 config;
+
if (reset)
w83795_write(client, W83795_REG_CONFIG, 0x80);
- /* Start monitoring */
- w83795_write(client, W83795_REG_CONFIG,
- w83795_read(client, W83795_REG_CONFIG) | 0x01);
+ /* Start monitoring if needed */
+ config = w83795_read(client, W83795_REG_CONFIG);
+ if (!(config & W83795_REG_CONFIG_START)) {
+ dev_info(&client->dev, "Enabling monitoring operations\n");
+ w83795_write(client, W83795_REG_CONFIG,
+ config | W83795_REG_CONFIG_START);
+ }
+
+ data->clkin = clkin[(config >> 3) & 0x3];
+ dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin);
}
static int w83795_get_device_id(struct i2c_client *client)
}
}
- for (i = 0; i < ARRAY_SIZE(w83795_static); i++) {
- err = fn(dev, &w83795_static[i].dev_attr);
- if (err)
- return err;
- }
-
return 0;
}
return 0;
}
+static void w83795_check_dynamic_in_limits(struct i2c_client *client)
+{
+ struct w83795_data *data = i2c_get_clientdata(client);
+ u8 vid_ctl;
+ int i, err_max, err_min;
+
+ vid_ctl = w83795_read(client, W83795_REG_VID_CTRL);
+
+ /* Return immediately if VRM isn't configured */
+ if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07)
+ return;
+
+ data->has_dyn_in = (vid_ctl >> 3) & 0x07;
+ for (i = 0; i < 2; i++) {
+ if (!(data->has_dyn_in & (1 << i)))
+ continue;
+
+ /* Voltage limits in dynamic mode, switch to read-only */
+ err_max = sysfs_chmod_file(&client->dev.kobj,
+ &w83795_in[i][2].dev_attr.attr,
+ S_IRUGO);
+ err_min = sysfs_chmod_file(&client->dev.kobj,
+ &w83795_in[i][3].dev_attr.attr,
+ S_IRUGO);
+ if (err_max || err_min)
+ dev_warn(&client->dev, "Failed to set in%d limits "
+ "read-only (%d, %d)\n", i, err_max, err_min);
+ else
+ dev_info(&client->dev, "in%d limits set dynamically "
+ "from VID\n", i);
+ }
+}
+
+/* Check pins that can be used for either temperature or voltage monitoring */
+static void w83795_apply_temp_config(struct w83795_data *data, u8 config,
+ int temp_chan, int in_chan)
+{
+ /* config is a 2-bit value */
+ switch (config) {
+ case 0x2: /* Voltage monitoring */
+ data->has_in |= 1 << in_chan;
+ break;
+ case 0x1: /* Thermal diode */
+ if (temp_chan >= 4)
+ break;
+ data->temp_mode |= 1 << temp_chan;
+ /* fall through */
+ case 0x3: /* Thermistor */
+ data->has_temp |= 1 << temp_chan;
+ break;
+ }
+}
+
static int w83795_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
u8 tmp;
struct device *dev = &client->dev;
struct w83795_data *data;
- int err = 0;
+ int err;
data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL);
if (!data) {
/* Initialize the chip */
w83795_init_client(client);
- data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1);
- data->has_in |= w83795_read(client, W83795_REG_VOLT_CTRL2) << 8;
- /* VSEN11-9 not for 795adg */
- if (data->chip_type == w83795adg)
- data->has_in &= 0xf8ff;
- data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1);
- data->has_fan |= w83795_read(client, W83795_REG_FANIN_CTRL2) << 8;
+ /* Check which voltages and fans are present */
+ data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1)
+ | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8);
+ data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1)
+ | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8);
- /* VDSEN12-17 and TR1-6, TD1-4 use same register */
+ /* Check which analog temperatures and extra voltages are present */
tmp = w83795_read(client, W83795_REG_TEMP_CTRL1);
if (tmp & 0x20)
data->enable_dts = 1;
- else
- data->enable_dts = 0;
- data->has_temp = 0;
- data->temp_mode = 0;
- if (tmp & 0x08) {
- if (tmp & 0x04)
- data->has_temp |= 0x20;
- else
- data->has_in |= 0x10000;
- }
- if (tmp & 0x02) {
- if (tmp & 0x01)
- data->has_temp |= 0x10;
- else
- data->has_in |= 0x8000;
- }
+ w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16);
+ w83795_apply_temp_config(data, tmp & 0x3, 4, 15);
tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
- if (tmp & 0x40) {
- data->has_temp |= 0x08;
- if (!(tmp & 0x80))
- data->temp_mode |= 0x08;
- } else if (tmp & 0x80) {
- data->has_in |= 0x100000;
- }
- if (tmp & 0x10) {
- data->has_temp |= 0x04;
- if (!(tmp & 0x20))
- data->temp_mode |= 0x04;
- } else if (tmp & 0x20) {
- data->has_in |= 0x80000;
- }
- if (tmp & 0x04) {
- data->has_temp |= 0x02;
- if (!(tmp & 0x08))
- data->temp_mode |= 0x02;
- } else if (tmp & 0x08) {
- data->has_in |= 0x40000;
- }
- if (tmp & 0x01) {
- data->has_temp |= 0x01;
- if (!(tmp & 0x02))
- data->temp_mode |= 0x01;
- } else if (tmp & 0x02) {
- data->has_in |= 0x20000;
- }
+ w83795_apply_temp_config(data, tmp >> 6, 3, 20);
+ w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19);
+ w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18);
+ w83795_apply_temp_config(data, tmp & 0x3, 0, 17);
/* Check DTS enable status */
- if (data->enable_dts == 0) {
- data->has_dts = 0;
- } else {
+ if (data->enable_dts) {
if (1 & w83795_read(client, W83795_REG_DTSC))
data->enable_dts |= 2;
data->has_dts = w83795_read(client, W83795_REG_DTSE);
data->fan_min[i] =
w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4;
data->fan_min[i] |=
- (w83795_read(client, W83795_REG_FAN_MIN_LSB(i) >>
- W83795_REG_FAN_MIN_LSB_SHIFT(i))) & 0x0F;
+ (w83795_read(client, W83795_REG_FAN_MIN_LSB(i)) >>
+ W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F;
data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
data->fan[i] |=
- (w83795_read(client, W83795_REG_VRLSB >> 4)) & 0x0F;
+ (w83795_read(client, W83795_REG_VRLSB) >> 4) & 0x0F;
}
/* temperature and limits */
data->has_pwm = 2;
data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1);
data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2);
- /* w83795adg only support pwm2-0 */
for (i = 0; i < W83795_REG_TEMP_NUM; i++)
data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i));
data->pwm_fomc = w83795_read(client, W83795_REG_FOMC);
if (err)
goto exit_remove;
+ if (data->chip_type == w83795g)
+ w83795_check_dynamic_in_limits(client);
+
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);