diff options
Diffstat (limited to 'drivers/hwmon/f75375s.c')
| -rw-r--r-- | drivers/hwmon/f75375s.c | 418 | 
1 files changed, 313 insertions, 105 deletions
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 95cbfb3a707..80c42bea90e 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -1,16 +1,19 @@  /* - * f75375s.c - driver for the Fintek F75375/SP and F75373 - *             hardware monitoring features + * f75375s.c - driver for the Fintek F75375/SP, F75373 and + *             F75387SG/RG hardware monitoring features   * Copyright (C) 2006-2007  Riku Voipio   *   * Datasheets available at:   *   * f75375: - * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf  + * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf   *   * f75373:   * 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   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License, or @@ -40,7 +43,7 @@  /* Addresses to scan */  static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; -enum chips { f75373, f75375 }; +enum chips { f75373, f75375, f75387 };  /* Fintek F75375 registers  */  #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_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_HYST(nr)	(0x29 + (nr) * 2) @@ -78,8 +82,11 @@ enum chips { f75373, f75375 };  #define F75375_REG_PWM1_DROP_DUTY	0x6B  #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 F75387_FAN_DUTY_MODE(nr)	(2 + ((nr) * 4)) +#define F75387_FAN_MANU_MODE(nr)	((nr) * 4)  /*   * Data structures and manipulation thereof @@ -102,13 +109,18 @@ struct f75375_data {  	u8 in_min[4];  	u16 fan[2];  	u16 fan_min[2]; -	u16 fan_full[2]; -	u16 fan_exp[2]; +	u16 fan_max[2]; +	u16 fan_target[2];  	u8 fan_timer;  	u8 pwm[2];  	u8 pwm_mode[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_max_hyst[2];  }; @@ -122,6 +134,7 @@ static int f75375_remove(struct i2c_client *client);  static const struct i2c_device_id f75375_id[] = {  	{ "f75373", f75373 },  	{ "f75375", f75375 }, +	{ "f75387", f75387 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, f75375_id); @@ -146,8 +159,8 @@ static inline int f75375_read8(struct i2c_client *client, u8 reg)  /* in most cases, should be called while holding update_lock */  static inline u16 f75375_read16(struct i2c_client *client, u8 reg)  { -	return ((i2c_smbus_read_byte_data(client, reg) << 8) -		| i2c_smbus_read_byte_data(client, reg + 1)); +	return (i2c_smbus_read_byte_data(client, reg) << 8) +		| i2c_smbus_read_byte_data(client, reg + 1);  }  static inline void f75375_write8(struct i2c_client *client, u8 reg, @@ -159,12 +172,22 @@ static inline void f75375_write8(struct i2c_client *client, u8 reg,  static inline void f75375_write16(struct i2c_client *client, u8 reg,  		u16 value)  { -	int err = i2c_smbus_write_byte_data(client, reg, (value << 8)); +	int err = i2c_smbus_write_byte_data(client, reg, (value >> 8));  	if (err)  		return;  	i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));  } +static void f75375_write_pwm(struct i2c_client *client, int nr) +{ +	struct f75375_data *data = i2c_get_clientdata(client); +	if (data->kind == f75387) +		f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]); +	else +		f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), +			      data->pwm[nr]); +} +  static struct f75375_data *f75375_update_device(struct device *dev)  {  	struct i2c_client *client = to_i2c_client(dev); @@ -181,15 +204,12 @@ static struct f75375_data *f75375_update_device(struct device *dev)  				f75375_read8(client, F75375_REG_TEMP_HIGH(nr));  			data->temp_max_hyst[nr] =  				f75375_read8(client, F75375_REG_TEMP_HYST(nr)); -			data->fan_full[nr] = +			data->fan_max[nr] =  				f75375_read16(client, F75375_REG_FAN_FULL(nr));  			data->fan_min[nr] =  				f75375_read16(client, F75375_REG_FAN_MIN(nr)); -			data->fan_exp[nr] = +			data->fan_target[nr] =  				f75375_read16(client, F75375_REG_FAN_EXP(nr)); -			data->pwm[nr] =	f75375_read8(client, -				F75375_REG_FAN_PWM_DUTY(nr)); -  		}  		for (nr = 0; nr < 4; nr++) {  			data->in_max[nr] = @@ -205,8 +225,16 @@ static struct f75375_data *f75375_update_device(struct device *dev)  	if (time_after(jiffies, data->last_updated + 2 * HZ)  		|| !data->valid) {  		for (nr = 0; nr < 2; nr++) { -			data->temp[nr] = -				f75375_read8(client, F75375_REG_TEMP(nr)); +			data->pwm[nr] =	f75375_read8(client, +				F75375_REG_FAN_PWM_DUTY(nr)); +			/* assign MSB, therefore shift it by 8 bits */ +			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] =  				f75375_read16(client, F75375_REG_FAN(nr));  		} @@ -226,14 +254,46 @@ static inline u16 rpm_from_reg(u16 reg)  {  	if (reg == 0 || reg == 0xffff)  		return 0; -	return (1500000 / reg); +	return 1500000 / reg;  }  static inline u16 rpm_to_reg(int rpm)  {  	if (rpm < 367 || rpm > 0xffff)  		return 0xffff; -	return (1500000 / rpm); +	return 1500000 / rpm; +} + +static bool duty_mode_enabled(u8 pwm_enable) +{ +	switch (pwm_enable) { +	case 0: /* Manual, duty mode (full speed) */ +	case 1: /* Manual, duty mode */ +	case 4: /* Auto, duty mode */ +		return true; +	case 2: /* Auto, speed mode */ +	case 3: /* Manual, speed mode */ +		return false; +	default: +		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); +		return true; +	} +} + +static bool auto_mode_enabled(u8 pwm_enable) +{ +	switch (pwm_enable) { +	case 0: /* Manual, duty mode (full speed) */ +	case 1: /* Manual, duty mode */ +	case 3: /* Manual, speed mode */ +		return false; +	case 2: /* Auto, speed mode */ +	case 4: /* Auto, duty mode */ +		return true; +	default: +		WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); +		return false; +	}  }  static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, @@ -242,7 +302,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err;  	mutex_lock(&data->update_lock);  	data->fan_min[nr] = rpm_to_reg(val); @@ -251,17 +316,27 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,  	return count;  } -static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr, +static ssize_t set_fan_target(struct device *dev, struct device_attribute *attr,  		const char *buf, size_t count)  {  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	if (auto_mode_enabled(data->pwm_enable[nr])) +		return -EINVAL; +	if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr])) +		return -EINVAL;  	mutex_lock(&data->update_lock); -	data->fan_exp[nr] = rpm_to_reg(val); -	f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]); +	data->fan_target[nr] = rpm_to_reg(val); +	f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]);  	mutex_unlock(&data->update_lock);  	return count;  } @@ -272,11 +347,20 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	if (auto_mode_enabled(data->pwm_enable[nr]) || +	    !duty_mode_enabled(data->pwm_enable[nr])) +		return -EINVAL;  	mutex_lock(&data->update_lock); -	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); -	f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]); +	data->pwm[nr] = clamp_val(val, 0, 255); +	f75375_write_pwm(client, nr);  	mutex_unlock(&data->update_lock);  	return count;  } @@ -298,26 +382,58 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)  		return -EINVAL;  	fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); -	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; +	if (data->kind == f75387) { +		/* For now, deny dangerous toggling of duty mode */ +		if (duty_mode_enabled(data->pwm_enable[nr]) != +				duty_mode_enabled(val)) +			return -EOPNOTSUPP; +		/* clear each fanX_mode bit before setting them properly */ +		fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr)); +		fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr)); +		switch (val) { +		case 0: /* full speed */ +			fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); +			fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); +			data->pwm[nr] = 255; +			break; +		case 1: /* PWM */ +			fanmode  |= (1 << F75387_FAN_MANU_MODE(nr)); +			fanmode  |= (1 << F75387_FAN_DUTY_MODE(nr)); +			break; +		case 2: /* Automatic, speed mode */ +			break; +		case 3: /* fan speed */ +			fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); +			break; +		case 4: /* Automatic, pwm */ +			fanmode |= (1 << F75387_FAN_DUTY_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; +			break; +		case 1: /* PWM */ +			fanmode  |= (3 << FAN_CTRL_MODE(nr)); +			break; +		case 2: /* AUTOMATIC*/ +			fanmode  |= (1 << FAN_CTRL_MODE(nr)); +			break; +		case 3: /* fan speed */ +			break; +		case 4: /* Automatic pwm */ +			return -EINVAL; +		}  	} +  	f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);  	data->pwm_enable[nr] = val; +	if (val == 0) +		f75375_write_pwm(client, nr);  	return 0;  } @@ -327,8 +443,12 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); -	int err = 0; +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err;  	mutex_lock(&data->update_lock);  	err = set_pwm_enable_direct(client, nr, val); @@ -342,20 +462,39 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); -	u8 conf = 0; +	unsigned long val; +	int err; +	u8 conf; +	char reg, ctrl; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err;  	if (!(val == 0 || val == 1))  		return -EINVAL; +	/* F75373 does not support DC (linear voltage) fan control mode */ +	if (data->kind == f75373 && val == 0) +		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); -	conf = f75375_read8(client, F75375_REG_CONFIG1); -	conf &= ~(1 << FAN_CTRL_LINEAR(nr)); +	conf = f75375_read8(client, reg); +	conf &= ~(1 << ctrl);  	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;  	mutex_unlock(&data->update_lock);  	return count; @@ -410,8 +549,14 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); -	val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);  	mutex_lock(&data->update_lock);  	data->in_max[nr] = val;  	f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]); @@ -425,8 +570,14 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtoul(buf, NULL, 10); -	val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);  	mutex_lock(&data->update_lock);  	data->in_min[nr] = val;  	f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]); @@ -435,13 +586,14 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,  }  #define TEMP_FROM_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)  {  	int nr = to_sensor_dev_attr(attr)->index;  	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, @@ -466,8 +618,14 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtol(buf, NULL, 10); -	val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	val = clamp_val(TEMP_TO_REG(val), 0, 127);  	mutex_lock(&data->update_lock);  	data->temp_high[nr] = val;  	f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]); @@ -481,8 +639,14 @@ static ssize_t set_temp_max_hyst(struct device *dev,  	int nr = to_sensor_dev_attr(attr)->index;  	struct i2c_client *client = to_i2c_client(dev);  	struct f75375_data *data = i2c_get_clientdata(client); -	int val = simple_strtol(buf, NULL, 10); -	val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); +	unsigned long val; +	int err; + +	err = kstrtoul(buf, 10, &val); +	if (err < 0) +		return err; + +	val = clamp_val(TEMP_TO_REG(val), 0, 127);  	mutex_lock(&data->update_lock);  	data->temp_max_hyst[nr] = val;  	f75375_write8(client, F75375_REG_TEMP_HYST(nr), @@ -502,8 +666,8 @@ static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \  show_fan(fan);  show_fan(fan_min); -show_fan(fan_full); -show_fan(fan_exp); +show_fan(fan_max); +show_fan(fan_target);  static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);  static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR, @@ -525,28 +689,28 @@ static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,  	show_in_max, set_in_max, 3);  static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,  	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,  	show_temp_max_hyst, set_temp_max_hyst, 0);  static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,  	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,  	show_temp_max_hyst, set_temp_max_hyst, 1);  static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,  	show_temp_max, set_temp_max, 1);  static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); -static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO, show_fan_max, NULL, 0);  static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,  	show_fan_min, set_fan_min, 0); -static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR, -	show_fan_exp, set_fan_exp, 0); +static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO|S_IWUSR, +	show_fan_target, set_fan_target, 0);  static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); -static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_max, S_IRUGO, show_fan_max, NULL, 1);  static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,  	show_fan_min, set_fan_min, 1); -static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR, -	show_fan_exp, set_fan_exp, 1); +static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO|S_IWUSR, +	show_fan_target, set_fan_target, 1);  static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,  	show_pwm, set_pwm, 0);  static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, @@ -568,13 +732,13 @@ static struct attribute *f75375_attributes[] = {  	&sensor_dev_attr_temp2_max.dev_attr.attr,  	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,  	&sensor_dev_attr_fan1_input.dev_attr.attr, -	&sensor_dev_attr_fan1_full.dev_attr.attr, +	&sensor_dev_attr_fan1_max.dev_attr.attr,  	&sensor_dev_attr_fan1_min.dev_attr.attr, -	&sensor_dev_attr_fan1_exp.dev_attr.attr, +	&sensor_dev_attr_fan1_target.dev_attr.attr,  	&sensor_dev_attr_fan2_input.dev_attr.attr, -	&sensor_dev_attr_fan2_full.dev_attr.attr, +	&sensor_dev_attr_fan2_max.dev_attr.attr,  	&sensor_dev_attr_fan2_min.dev_attr.attr, -	&sensor_dev_attr_fan2_exp.dev_attr.attr, +	&sensor_dev_attr_fan2_target.dev_attr.attr,  	&sensor_dev_attr_pwm1.dev_attr.attr,  	&sensor_dev_attr_pwm1_enable.dev_attr.attr,  	&sensor_dev_attr_pwm1_mode.dev_attr.attr, @@ -604,12 +768,62 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,  		struct f75375s_platform_data *f75375s_pdata)  {  	int nr; + +	if (!f75375s_pdata) { +		u8 conf, mode; +		int nr; + +		conf = f75375_read8(client, F75375_REG_CONFIG1); +		mode = f75375_read8(client, F75375_REG_FAN_TIMER); +		for (nr = 0; nr < 2; nr++) { +			if (data->kind == f75387) { +				bool manu, duty; + +				if (!(mode & (1 << F75387_FAN_CTRL_LINEAR(nr)))) +					data->pwm_mode[nr] = 1; + +				manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1); +				duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1); +				if (!manu && duty) +					/* auto, pwm */ +					data->pwm_enable[nr] = 4; +				else if (manu && !duty) +					/* manual, speed */ +					data->pwm_enable[nr] = 3; +				else if (!manu && !duty) +					/* automatic, speed */ +					data->pwm_enable[nr] = 2; +				else +					/* manual, pwm */ +					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; +	} +  	set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);  	set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);  	for (nr = 0; nr < 2; nr++) { -		data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255); -		f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), -			data->pwm[nr]); +		if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) || +		    !duty_mode_enabled(f75375s_pdata->pwm_enable[nr])) +			continue; +		data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255); +		f75375_write_pwm(client, nr);  	}  } @@ -618,23 +832,27 @@ static int f75375_probe(struct i2c_client *client,  		const struct i2c_device_id *id)  {  	struct f75375_data *data; -	struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data; +	struct f75375s_platform_data *f75375s_pdata = +			dev_get_platdata(&client->dev);  	int err;  	if (!i2c_check_functionality(client->adapter,  				I2C_FUNC_SMBUS_BYTE_DATA))  		return -EIO; -	if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) +	data = devm_kzalloc(&client->dev, sizeof(struct f75375_data), +			    GFP_KERNEL); +	if (!data)  		return -ENOMEM;  	i2c_set_clientdata(client, data);  	mutex_init(&data->update_lock);  	data->kind = id->driver_data; -	if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) -		goto exit_free; +	err = sysfs_create_group(&client->dev.kobj, &f75375_group); +	if (err) +		return err; -	if (data->kind == f75375) { +	if (data->kind != f75373) {  		err = sysfs_chmod_file(&client->dev.kobj,  			&sensor_dev_attr_pwm1_mode.dev_attr.attr,  			S_IRUGO | S_IWUSR); @@ -653,15 +871,12 @@ static int f75375_probe(struct i2c_client *client,  		goto exit_remove;  	} -	if (f75375s_pdata != NULL) -		f75375_init(client, data, f75375s_pdata); +	f75375_init(client, data, f75375s_pdata);  	return 0;  exit_remove:  	sysfs_remove_group(&client->dev.kobj, &f75375_group); -exit_free: -	kfree(data);  	return err;  } @@ -670,7 +885,6 @@ static int f75375_remove(struct i2c_client *client)  	struct f75375_data *data = i2c_get_clientdata(client);  	hwmon_device_unregister(data->hwmon_dev);  	sysfs_remove_group(&client->dev.kobj, &f75375_group); -	kfree(data);  	return 0;  } @@ -685,10 +899,15 @@ static int f75375_detect(struct i2c_client *client,  	vendid = f75375_read16(client, F75375_REG_VENDOR);  	chipid = f75375_read16(client, F75375_CHIP_ID); -	if (chipid == 0x0306 && vendid == 0x1934) +	if (vendid != 0x1934) +		return -ENODEV; + +	if (chipid == 0x0306)  		name = "f75375"; -	else if (chipid == 0x0204 && vendid == 0x1934) +	else if (chipid == 0x0204)  		name = "f75373"; +	else if (chipid == 0x0410) +		name = "f75387";  	else  		return -ENODEV; @@ -699,19 +918,8 @@ static int f75375_detect(struct i2c_client *client,  	return 0;  } -static int __init sensors_f75375_init(void) -{ -	return i2c_add_driver(&f75375_driver); -} - -static void __exit sensors_f75375_exit(void) -{ -	i2c_del_driver(&f75375_driver); -} +module_i2c_driver(f75375_driver);  MODULE_AUTHOR("Riku Voipio");  MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver"); - -module_init(sensors_f75375_init); -module_exit(sensors_f75375_exit); +MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver");  | 
