Pwm clock selection and scaling registers was added for w83627hf and w83697hf. At the moment only for 2.6 drivers... the patch has been obtained using 2.6.17.3 source. It gives direct access to the registers and only cares about reserved registers, not about data format. For example, the w83627hf clock selection register for pwm1 and pwm2 is mapped in a single register. I didnt format the register output to show single values for every pwm, but the registers contents. I think its better this way because the user/program reading or modifying this values is suppossed to know the format anyway. here it goes, next patch will enable this features in libsensors... I will also take a look to add support for w83627thf, w83637hf and w83687thf. Carlos http://www.tinet.org/~com.ea/ ================== --- w83627hf.orig.c 2006-06-30 19:37:38.000000000 +0200 +++ w83627hf.new.c 2006-07-05 17:43:31.000000000 +0200 @@ -219,6 +219,15 @@ static const u8 regpwm[] = { W83627THF_R W83627THF_REG_PWM3 }; #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) + +#define W83697HF_REG_PWMCLK1 0x00 /* Only for the 697HF */ +#define W83697HF_REG_PWMCLK2 0x02 /* Only for the 697HF */ + +static const u8 reg_pwmclk_697hf[] = {W83697HF_REG_PWMCLK1, W83697HF_REG_PWMCLK2}; + +#define W83627HF_REG_PWMCLK12 0x5C /* Only for the 627HF */ + +// To do : w83627thf, w83637hf and w83687thf pwmclk support #define W83781D_REG_I2C_ADDR 0x48 #define W83781D_REG_I2C_SUBADDR 0x4A @@ -319,6 +328,7 @@ struct w83627hf_data { u32 beep_mask; /* Register encoding, combined */ u8 beep_enable; /* Boolean */ u8 pwm[3]; /* Register value */ + u8 pwmclk[3]; /* Register value */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; 3000-5000 = thermistor beta. @@ -901,6 +911,68 @@ device_create_file(&client->dev, &dev_at } while (0) static ssize_t +show_pwmclk_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwmclk[nr - 1]); +} + +static ssize_t +store_pwmclk_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + if (data->type == w83627hf) { + /* bits 7 and 3 are reserved */ + data->pwmclk[nr - 1] = PWM_TO_REG(val) & 0x77; + /* bits 6..4 pwmclk2 .. bits 2..0 pwmclk1 */ + w83627hf_write_value(client, + W83627HF_REG_PWMCLK12, + data->pwmclk[nr - 1] | + (w83627hf_read_value(client, + W83627HF_REG_PWMCLK12) & 0x88)); + } else if (data->type == w83697hf) { + data->pwmclk[nr - 1] = PWM_TO_REG(val); + w83627hf_write_value(client, + reg_pwmclk_697hf[nr - 1], + data->pwmclk[nr - 1]); + } else { + /* TODO w83627thf, w83637hf and w83687thf */ + } + + mutex_unlock(&data->update_lock); + return count; +} + +#define sysfs_pwmclk(offset) \ +static ssize_t show_regs_pwmclk_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwmclk_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_pwmclk_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_pwmclk_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwmclk##offset, S_IRUGO | S_IWUSR, \ + show_regs_pwmclk_##offset, store_regs_pwmclk_##offset); + +sysfs_pwmclk(1); +sysfs_pwmclk(2); +// sysfs_pwmclk(3); /* TODO w83627thf, w83637hf and w83687thf */ + +#define device_create_file_pwmclk(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwmclk##offset); \ +} while (0) + +static ssize_t show_sensor_reg(struct device *dev, char *buf, int nr) { struct w83627hf_data *data = w83627hf_update_device(dev); @@ -1155,6 +1227,15 @@ static int w83627hf_detect(struct i2c_ad device_create_file_pwm(new_client, 2); if (kind == w83627thf || kind == w83637hf || kind == w83687thf) device_create_file_pwm(new_client, 3); + + if (kind == w83697hf) { + device_create_file_pwmclk(new_client, 1); + device_create_file_pwmclk(new_client, 2); + } else if (kind == w83627hf) { + device_create_file_pwmclk(new_client, 1); + } else { + /* TODO w83627thf, w83637hf and w83687thf */ + } device_create_file_sensor(new_client, 1); device_create_file_sensor(new_client, 2); @@ -1469,6 +1550,18 @@ static struct w83627hf_data *w83627hf_up break; } + if ( data->type == w83697hf ) { + for (i = 1; i <= 2; i++) { + u8 tmp = w83627hf_read_value(client,reg_pwmclk_697hf[i-1]); + data->pwmclk[i - 1] = tmp; + } + } else if ( data->type == w83627hf ) { + u8 tmp = w83627hf_read_value(client,W83627HF_REG_PWMCLK12); + data->pwmclk[0] = tmp; + } else { + /* TODO w83627thf, w83637hf and w83687thf */ + } + data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); data->temp_max = w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));