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 /drivers/hwmon/w83795.c | |
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>
Diffstat (limited to 'drivers/hwmon/w83795.c')
-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) |