Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1550cb6d authored by Carlos Olalla Martinez's avatar Carlos Olalla Martinez Committed by Mark M. Hoffman
Browse files

hwmon/w83627hf: Add PWM frequency selection support

parent 08a8f6e9
Loading
Loading
Loading
Loading
+140 −1
Original line number Diff line number Diff line
@@ -220,6 +220,18 @@ static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])

#define W83627HF_REG_PWM_FREQ		0x5C	/* Only for the 627HF */

#define W83637HF_REG_PWM_FREQ1		0x00	/* 697HF/687THF too */
#define W83637HF_REG_PWM_FREQ2		0x02	/* 697HF/687THF too */
#define W83637HF_REG_PWM_FREQ3		0x10	/* 687THF too */

static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
					W83637HF_REG_PWM_FREQ2,
					W83637HF_REG_PWM_FREQ3 };

#define W83627HF_BASE_PWM_FREQ	46870

#define W83781D_REG_I2C_ADDR 0x48
#define W83781D_REG_I2C_SUBADDR 0x4A

@@ -267,6 +279,49 @@ static int TEMP_FROM_REG(u8 reg)

#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))

static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
{
	unsigned long freq;
	freq = W83627HF_BASE_PWM_FREQ >> reg;
	return freq;
}
static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
{
	u8 i;
	/* Only 5 dividers (1 2 4 8 16)
	   Search for the nearest available frequency */
	for (i = 0; i < 4; i++) {
		if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
			    (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
			break;
	}
	return i;
}

static inline unsigned long pwm_freq_from_reg(u8 reg)
{
	/* Clock bit 8 -> 180 kHz or 24 MHz */
	unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;

	reg &= 0x7f;
	/* This should not happen but anyway... */
	if (reg == 0)
		reg++;
	return (clock / (reg << 8));
}
static inline u8 pwm_freq_to_reg(unsigned long val)
{
	/* Minimum divider value is 0x01 and maximum is 0x7F */
	if (val >= 93750)	/* The highest we can do */
		return 0x01;
	if (val >= 720)	/* Use 24 MHz clock */
		return (24000000UL / (val << 8));
	if (val < 6)		/* The lowest we can do */
		return 0xFF;
	else			/* Use 180 kHz clock */
		return (0x80 | (180000UL / (val << 8)));
}

#define BEEP_MASK_FROM_REG(val)		 (val)
#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
@@ -316,6 +371,7 @@ struct w83627hf_data {
	u32 beep_mask;		/* Register encoding, combined */
	u8 beep_enable;		/* Boolean */
	u8 pwm[3];		/* Register value */
	u8 pwm_freq[3];		/* Register value */
	u16 sens[3];		/* 782D/783S only.
				   1 = pentium diode; 2 = 3904 diode;
				   3000-5000 = thermistor beta.
@@ -851,6 +907,64 @@ sysfs_pwm(1);
sysfs_pwm(2);
sysfs_pwm(3);

static ssize_t
show_pwm_freq_reg(struct device *dev, char *buf, int nr)
{
	struct w83627hf_data *data = w83627hf_update_device(dev);
	if (data->type == w83627hf)
		return sprintf(buf, "%ld\n",
			pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
	else
		return sprintf(buf, "%ld\n",
			pwm_freq_from_reg(data->pwm_freq[nr - 1]));
}

static ssize_t
store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
{
	struct w83627hf_data *data = dev_get_drvdata(dev);
	static const u8 mask[]={0xF8, 0x8F};
	u32 val;

	val = simple_strtoul(buf, NULL, 10);

	mutex_lock(&data->update_lock);

	if (data->type == w83627hf) {
		data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
		w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
				(data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
				(w83627hf_read_value(data,
				W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
	} else {
		data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
		w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
				data->pwm_freq[nr - 1]);
	}

	mutex_unlock(&data->update_lock);
	return count;
}

#define sysfs_pwm_freq(offset) \
static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
		struct device_attribute *attr, char *buf) \
{ \
	return show_pwm_freq_reg(dev, buf, offset); \
} \
static ssize_t \
store_regs_pwm_freq_##offset(struct device *dev, \
		struct device_attribute *attr, const char *buf, size_t count) \
{ \
	return store_pwm_freq_reg(dev, buf, count, offset); \
} \
static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
		  show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);

sysfs_pwm_freq(1);
sysfs_pwm_freq(2);
sysfs_pwm_freq(3);

static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@@ -1077,6 +1191,9 @@ static struct attribute *w83627hf_attributes_opt[] = {

	&dev_attr_pwm3.attr,

	&dev_attr_pwm1_freq.attr,
	&dev_attr_pwm2_freq.attr,
	&dev_attr_pwm3_freq.attr,
	NULL
};

@@ -1139,7 +1256,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
		 || (err = device_create_file(dev, &dev_attr_in5_max))
		 || (err = device_create_file(dev, &dev_attr_in6_input))
		 || (err = device_create_file(dev, &dev_attr_in6_min))
		 || (err = device_create_file(dev, &dev_attr_in6_max)))
		 || (err = device_create_file(dev, &dev_attr_in6_max))
		 || (err = device_create_file(dev, &dev_attr_pwm1_freq))
		 || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
			goto ERROR4;

	if (data->type != w83697hf)
@@ -1169,6 +1288,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
		if ((err = device_create_file(dev, &dev_attr_pwm3)))
			goto ERROR4;

	if (data->type == w83637hf || data->type == w83687thf)
		if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
		 || (err = device_create_file(dev, &dev_attr_pwm2_freq))
		 || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
			goto ERROR4;

	data->class_dev = hwmon_device_register(dev);
	if (IS_ERR(data->class_dev)) {
		err = PTR_ERR(data->class_dev);
@@ -1472,6 +1597,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
			   (data->type == w83627hf || data->type == w83697hf))
				break;
		}
		if (data->type == w83627hf) {
				u8 tmp = w83627hf_read_value(data,
						W83627HF_REG_PWM_FREQ);
				data->pwm_freq[0] = tmp & 0x07;
				data->pwm_freq[1] = (tmp >> 4) & 0x07;
		} else if (data->type != w83627thf) {
			for (i = 1; i <= 3; i++) {
				data->pwm_freq[i - 1] =
					w83627hf_read_value(data,
						W83637HF_REG_PWM_FREQ[i - 1]);
				if (i == 2 && (data->type == w83697hf))
					break;
			}
		}

		data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
		data->temp_max =