diff options
| author | Jean Delvare <khali@linux-fr.org> | 2010-10-28 14:31:47 -0400 |
|---|---|---|
| committer | Jean Delvare <khali@endymion.delvare> | 2010-10-28 14:31:47 -0400 |
| commit | 01879a855fb6bdb3fb820344a7a145de8a5cdbda (patch) | |
| tree | 152e9a958bfdd71692455d18348623b1cbb40929 | |
| parent | 0e256018b0f35d1b22ca37e1d0e207f7ba3d0076 (diff) | |
hwmon: (w83795) Fix PWM duty cycle frequency attributes
The PWM duty cycle frequenty attributes are improperly named
(fanN_div instead of pwmN_div) and contain raw values instead of
actual frequencies. Rename them and fix their contents.
Also improve the logic when the user asks for a new frequency, to
always pick the closest supported frequency. The algorithm could
certainly be optimized, but the operation is infrequent enough that
I don't think it's worth the effort.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
| -rw-r--r-- | drivers/hwmon/w83795.c | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 458fb297f696..58c61f11ed66 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c | |||
| @@ -200,7 +200,6 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { | |||
| 200 | #define W83795_REG_FCMS2 0x208 | 200 | #define W83795_REG_FCMS2 0x208 |
| 201 | #define W83795_REG_TFMR(index) (0x202 + (index)) | 201 | #define W83795_REG_TFMR(index) (0x202 + (index)) |
| 202 | #define W83795_REG_FOMC 0x20F | 202 | #define W83795_REG_FOMC 0x20F |
| 203 | #define W83795_REG_FOPFP(index) (0x218 + (index)) | ||
| 204 | 203 | ||
| 205 | #define W83795_REG_TSS(index) (0x209 + (index)) | 204 | #define W83795_REG_TSS(index) (0x209 + (index)) |
| 206 | 205 | ||
| @@ -208,18 +207,13 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = { | |||
| 208 | #define PWM_START 1 | 207 | #define PWM_START 1 |
| 209 | #define PWM_NONSTOP 2 | 208 | #define PWM_NONSTOP 2 |
| 210 | #define PWM_STOP_TIME 3 | 209 | #define PWM_STOP_TIME 3 |
| 211 | #define PWM_DIV 4 | 210 | #define PWM_FREQ 4 |
| 212 | #define W83795_REG_PWM(index, nr) \ | 211 | #define W83795_REG_PWM(index, nr) \ |
| 213 | (((nr) == 0 ? 0x210 : \ | 212 | (((nr) == 0 ? 0x210 : \ |
| 214 | (nr) == 1 ? 0x220 : \ | 213 | (nr) == 1 ? 0x220 : \ |
| 215 | (nr) == 2 ? 0x228 : \ | 214 | (nr) == 2 ? 0x228 : \ |
| 216 | (nr) == 3 ? 0x230 : 0x218) + (index)) | 215 | (nr) == 3 ? 0x230 : 0x218) + (index)) |
| 217 | 216 | ||
| 218 | #define W83795_REG_FOPFP_DIV(index) \ | ||
| 219 | (((index) < 8) ? ((index) + 1) : \ | ||
| 220 | ((index) == 8) ? 12 : \ | ||
| 221 | (16 << ((index) - 9))) | ||
| 222 | |||
| 223 | #define W83795_REG_FTSH(index) (0x240 + (index) * 2) | 217 | #define W83795_REG_FTSH(index) (0x240 + (index) * 2) |
| 224 | #define W83795_REG_FTSL(index) (0x241 + (index) * 2) | 218 | #define W83795_REG_FTSL(index) (0x241 + (index) * 2) |
| 225 | #define W83795_REG_TFTS 0x250 | 219 | #define W83795_REG_TFTS 0x250 |
| @@ -304,6 +298,50 @@ static inline s8 temp_to_reg(long val, s8 min, s8 max) | |||
| 304 | return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); | 298 | return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max); |
| 305 | } | 299 | } |
| 306 | 300 | ||
| 301 | static const u16 pwm_freq_cksel0[16] = { | ||
| 302 | 1024, 512, 341, 256, 205, 171, 146, 128, | ||
| 303 | 85, 64, 32, 16, 8, 4, 2, 1 | ||
| 304 | }; | ||
| 305 | |||
| 306 | static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) | ||
| 307 | { | ||
| 308 | unsigned long base_clock; | ||
| 309 | |||
| 310 | if (reg & 0x80) { | ||
| 311 | base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); | ||
| 312 | return base_clock / ((reg & 0x7f) + 1); | ||
| 313 | } else | ||
| 314 | return pwm_freq_cksel0[reg & 0x0f]; | ||
| 315 | } | ||
| 316 | |||
| 317 | static u8 pwm_freq_to_reg(unsigned long val, u16 clkin) | ||
| 318 | { | ||
| 319 | unsigned long base_clock; | ||
| 320 | u8 reg0, reg1; | ||
| 321 | unsigned long best0, best1; | ||
| 322 | |||
| 323 | /* Best fit for cksel = 0 */ | ||
| 324 | for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) { | ||
| 325 | if (val > (pwm_freq_cksel0[reg0] + | ||
| 326 | pwm_freq_cksel0[reg0 + 1]) / 2) | ||
| 327 | break; | ||
| 328 | } | ||
| 329 | if (val < 375) /* cksel = 1 can't beat this */ | ||
| 330 | return reg0; | ||
| 331 | best0 = pwm_freq_cksel0[reg0]; | ||
| 332 | |||
| 333 | /* Best fit for cksel = 1 */ | ||
| 334 | base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); | ||
| 335 | reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); | ||
| 336 | best1 = base_clock / reg1; | ||
| 337 | reg1 = 0x80 | (reg1 - 1); | ||
| 338 | |||
| 339 | /* Choose the closest one */ | ||
| 340 | if (abs(val - best0) > abs(val - best1)) | ||
| 341 | return reg1; | ||
| 342 | else | ||
| 343 | return reg0; | ||
| 344 | } | ||
| 307 | 345 | ||
| 308 | enum chip_types {w83795g, w83795adg}; | 346 | enum chip_types {w83795g, w83795adg}; |
| 309 | 347 | ||
| @@ -343,7 +381,8 @@ struct w83795_data { | |||
| 343 | * no config register, only affected by chip | 381 | * no config register, only affected by chip |
| 344 | * type */ | 382 | * type */ |
| 345 | u8 pwm[8][5]; /* Register value, output, start, non stop, stop | 383 | u8 pwm[8][5]; /* Register value, output, start, non stop, stop |
| 346 | * time, div */ | 384 | * time, freq */ |
| 385 | u16 clkin; /* CLKIN frequency in kHz */ | ||
| 347 | u8 pwm_fcms[2]; /* Register value */ | 386 | u8 pwm_fcms[2]; /* Register value */ |
| 348 | u8 pwm_tfmr[6]; /* Register value */ | 387 | u8 pwm_tfmr[6]; /* Register value */ |
| 349 | u8 pwm_fomc; /* Register value */ | 388 | u8 pwm_fomc; /* Register value */ |
| @@ -688,14 +727,14 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf) | |||
| 688 | to_sensor_dev_attr_2(attr); | 727 | to_sensor_dev_attr_2(attr); |
| 689 | int nr = sensor_attr->nr; | 728 | int nr = sensor_attr->nr; |
| 690 | int index = sensor_attr->index; | 729 | int index = sensor_attr->index; |
| 691 | u16 val; | 730 | unsigned int val; |
| 692 | 731 | ||
| 693 | switch (nr) { | 732 | switch (nr) { |
| 694 | case PWM_STOP_TIME: | 733 | case PWM_STOP_TIME: |
| 695 | val = time_from_reg(data->pwm[index][nr]); | 734 | val = time_from_reg(data->pwm[index][nr]); |
| 696 | break; | 735 | break; |
| 697 | case PWM_DIV: | 736 | case PWM_FREQ: |
| 698 | val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f); | 737 | val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); |
| 699 | break; | 738 | break; |
| 700 | default: | 739 | default: |
| 701 | val = data->pwm[index][nr]; | 740 | val = data->pwm[index][nr]; |
| @@ -716,7 +755,6 @@ store_pwm(struct device *dev, struct device_attribute *attr, | |||
| 716 | int nr = sensor_attr->nr; | 755 | int nr = sensor_attr->nr; |
| 717 | int index = sensor_attr->index; | 756 | int index = sensor_attr->index; |
| 718 | unsigned long val; | 757 | unsigned long val; |
| 719 | int i; | ||
| 720 | 758 | ||
| 721 | if (strict_strtoul(buf, 10, &val) < 0) | 759 | if (strict_strtoul(buf, 10, &val) < 0) |
| 722 | return -EINVAL; | 760 | return -EINVAL; |
| @@ -726,28 +764,17 @@ store_pwm(struct device *dev, struct device_attribute *attr, | |||
| 726 | case PWM_STOP_TIME: | 764 | case PWM_STOP_TIME: |
| 727 | val = time_to_reg(val); | 765 | val = time_to_reg(val); |
| 728 | break; | 766 | break; |
| 729 | case PWM_DIV: | 767 | case PWM_FREQ: |
| 730 | for (i = 0; i < 16; i++) { | 768 | val = pwm_freq_to_reg(val, data->clkin); |
| 731 | if (W83795_REG_FOPFP_DIV(i) == val) { | ||
| 732 | val = i; | ||
| 733 | break; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | if (i >= 16) | ||
| 737 | goto err_end; | ||
| 738 | val |= w83795_read(client, W83795_REG_PWM(index, nr)) & 0x80; | ||
| 739 | break; | 769 | break; |
| 740 | default: | 770 | default: |
| 741 | val = SENSORS_LIMIT(val, 0, 0xff); | 771 | val = SENSORS_LIMIT(val, 0, 0xff); |
| 742 | break; | 772 | break; |
| 743 | } | 773 | } |
| 744 | w83795_write(client, W83795_REG_PWM(index, nr), val); | 774 | w83795_write(client, W83795_REG_PWM(index, nr), val); |
| 745 | data->pwm[index][nr] = val & 0xff; | 775 | data->pwm[index][nr] = val; |
| 746 | mutex_unlock(&data->update_lock); | 776 | mutex_unlock(&data->update_lock); |
| 747 | return count; | 777 | return count; |
| 748 | err_end: | ||
| 749 | mutex_unlock(&data->update_lock); | ||
| 750 | return -EINVAL; | ||
| 751 | } | 778 | } |
| 752 | 779 | ||
| 753 | static ssize_t | 780 | static ssize_t |
| @@ -1502,8 +1529,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, | |||
| 1502 | show_pwm, store_pwm, PWM_START, index - 1), \ | 1529 | show_pwm, store_pwm, PWM_START, index - 1), \ |
| 1503 | SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ | 1530 | SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ |
| 1504 | show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ | 1531 | show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ |
| 1505 | SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \ | 1532 | SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ |
| 1506 | show_pwm, store_pwm, PWM_DIV, index - 1), \ | 1533 | show_pwm, store_pwm, PWM_FREQ, index - 1), \ |
| 1507 | SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ | 1534 | SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ |
| 1508 | show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ | 1535 | show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ |
| 1509 | SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ | 1536 | SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ |
| @@ -1685,6 +1712,10 @@ static const struct sensor_device_attribute_2 sda_single_files[] = { | |||
| 1685 | 1712 | ||
| 1686 | static void w83795_init_client(struct i2c_client *client) | 1713 | static void w83795_init_client(struct i2c_client *client) |
| 1687 | { | 1714 | { |
| 1715 | struct w83795_data *data = i2c_get_clientdata(client); | ||
| 1716 | static const u16 clkin[4] = { /* in kHz */ | ||
| 1717 | 14318, 24000, 33333, 48000 | ||
| 1718 | }; | ||
| 1688 | u8 config; | 1719 | u8 config; |
| 1689 | 1720 | ||
| 1690 | if (reset) | 1721 | if (reset) |
| @@ -1697,6 +1728,9 @@ static void w83795_init_client(struct i2c_client *client) | |||
| 1697 | w83795_write(client, W83795_REG_CONFIG, | 1728 | w83795_write(client, W83795_REG_CONFIG, |
| 1698 | config | W83795_REG_CONFIG_START); | 1729 | config | W83795_REG_CONFIG_START); |
| 1699 | } | 1730 | } |
| 1731 | |||
| 1732 | data->clkin = clkin[(config >> 3) & 0x3]; | ||
| 1733 | dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); | ||
| 1700 | } | 1734 | } |
| 1701 | 1735 | ||
| 1702 | static int w83795_get_device_id(struct i2c_client *client) | 1736 | static int w83795_get_device_id(struct i2c_client *client) |
