diff options
Diffstat (limited to 'drivers/hwmon/f75375s.c')
-rw-r--r-- | drivers/hwmon/f75375s.c | 103 |
1 files changed, 81 insertions, 22 deletions
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index eedf574ab539..6aa5a9fad879 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c | |||
@@ -172,12 +172,22 @@ static inline void f75375_write8(struct i2c_client *client, u8 reg, | |||
172 | static inline void f75375_write16(struct i2c_client *client, u8 reg, | 172 | static inline void f75375_write16(struct i2c_client *client, u8 reg, |
173 | u16 value) | 173 | u16 value) |
174 | { | 174 | { |
175 | int err = i2c_smbus_write_byte_data(client, reg, (value << 8)); | 175 | int err = i2c_smbus_write_byte_data(client, reg, (value >> 8)); |
176 | if (err) | 176 | if (err) |
177 | return; | 177 | return; |
178 | i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); | 178 | i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); |
179 | } | 179 | } |
180 | 180 | ||
181 | static void f75375_write_pwm(struct i2c_client *client, int nr) | ||
182 | { | ||
183 | struct f75375_data *data = i2c_get_clientdata(client); | ||
184 | if (data->kind == f75387) | ||
185 | f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]); | ||
186 | else | ||
187 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), | ||
188 | data->pwm[nr]); | ||
189 | } | ||
190 | |||
181 | static struct f75375_data *f75375_update_device(struct device *dev) | 191 | static struct f75375_data *f75375_update_device(struct device *dev) |
182 | { | 192 | { |
183 | struct i2c_client *client = to_i2c_client(dev); | 193 | struct i2c_client *client = to_i2c_client(dev); |
@@ -200,9 +210,6 @@ static struct f75375_data *f75375_update_device(struct device *dev) | |||
200 | f75375_read16(client, F75375_REG_FAN_MIN(nr)); | 210 | f75375_read16(client, F75375_REG_FAN_MIN(nr)); |
201 | data->fan_target[nr] = | 211 | data->fan_target[nr] = |
202 | f75375_read16(client, F75375_REG_FAN_EXP(nr)); | 212 | f75375_read16(client, F75375_REG_FAN_EXP(nr)); |
203 | data->pwm[nr] = f75375_read8(client, | ||
204 | F75375_REG_FAN_PWM_DUTY(nr)); | ||
205 | |||
206 | } | 213 | } |
207 | for (nr = 0; nr < 4; nr++) { | 214 | for (nr = 0; nr < 4; nr++) { |
208 | data->in_max[nr] = | 215 | data->in_max[nr] = |
@@ -218,6 +225,8 @@ static struct f75375_data *f75375_update_device(struct device *dev) | |||
218 | if (time_after(jiffies, data->last_updated + 2 * HZ) | 225 | if (time_after(jiffies, data->last_updated + 2 * HZ) |
219 | || !data->valid) { | 226 | || !data->valid) { |
220 | for (nr = 0; nr < 2; nr++) { | 227 | for (nr = 0; nr < 2; nr++) { |
228 | data->pwm[nr] = f75375_read8(client, | ||
229 | F75375_REG_FAN_PWM_DUTY(nr)); | ||
221 | /* assign MSB, therefore shift it by 8 bits */ | 230 | /* assign MSB, therefore shift it by 8 bits */ |
222 | data->temp11[nr] = | 231 | data->temp11[nr] = |
223 | f75375_read8(client, F75375_REG_TEMP(nr)) << 8; | 232 | f75375_read8(client, F75375_REG_TEMP(nr)) << 8; |
@@ -255,6 +264,36 @@ static inline u16 rpm_to_reg(int rpm) | |||
255 | return 1500000 / rpm; | 264 | return 1500000 / rpm; |
256 | } | 265 | } |
257 | 266 | ||
267 | static bool duty_mode_enabled(u8 pwm_enable) | ||
268 | { | ||
269 | switch (pwm_enable) { | ||
270 | case 0: /* Manual, duty mode (full speed) */ | ||
271 | case 1: /* Manual, duty mode */ | ||
272 | case 4: /* Auto, duty mode */ | ||
273 | return true; | ||
274 | case 2: /* Auto, speed mode */ | ||
275 | case 3: /* Manual, speed mode */ | ||
276 | return false; | ||
277 | default: | ||
278 | BUG(); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static bool auto_mode_enabled(u8 pwm_enable) | ||
283 | { | ||
284 | switch (pwm_enable) { | ||
285 | case 0: /* Manual, duty mode (full speed) */ | ||
286 | case 1: /* Manual, duty mode */ | ||
287 | case 3: /* Manual, speed mode */ | ||
288 | return false; | ||
289 | case 2: /* Auto, speed mode */ | ||
290 | case 4: /* Auto, duty mode */ | ||
291 | return true; | ||
292 | default: | ||
293 | BUG(); | ||
294 | } | ||
295 | } | ||
296 | |||
258 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, | 297 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, |
259 | const char *buf, size_t count) | 298 | const char *buf, size_t count) |
260 | { | 299 | { |
@@ -288,6 +327,11 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *attr, | |||
288 | if (err < 0) | 327 | if (err < 0) |
289 | return err; | 328 | return err; |
290 | 329 | ||
330 | if (auto_mode_enabled(data->pwm_enable[nr])) | ||
331 | return -EINVAL; | ||
332 | if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr])) | ||
333 | return -EINVAL; | ||
334 | |||
291 | mutex_lock(&data->update_lock); | 335 | mutex_lock(&data->update_lock); |
292 | data->fan_target[nr] = rpm_to_reg(val); | 336 | data->fan_target[nr] = rpm_to_reg(val); |
293 | f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]); | 337 | f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]); |
@@ -308,9 +352,13 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | |||
308 | if (err < 0) | 352 | if (err < 0) |
309 | return err; | 353 | return err; |
310 | 354 | ||
355 | if (auto_mode_enabled(data->pwm_enable[nr]) || | ||
356 | !duty_mode_enabled(data->pwm_enable[nr])) | ||
357 | return -EINVAL; | ||
358 | |||
311 | mutex_lock(&data->update_lock); | 359 | mutex_lock(&data->update_lock); |
312 | data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); | 360 | data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); |
313 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]); | 361 | f75375_write_pwm(client, nr); |
314 | mutex_unlock(&data->update_lock); | 362 | mutex_unlock(&data->update_lock); |
315 | return count; | 363 | return count; |
316 | } | 364 | } |
@@ -328,11 +376,15 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) | |||
328 | struct f75375_data *data = i2c_get_clientdata(client); | 376 | struct f75375_data *data = i2c_get_clientdata(client); |
329 | u8 fanmode; | 377 | u8 fanmode; |
330 | 378 | ||
331 | if (val < 0 || val > 3) | 379 | if (val < 0 || val > 4) |
332 | return -EINVAL; | 380 | return -EINVAL; |
333 | 381 | ||
334 | fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); | 382 | fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); |
335 | if (data->kind == f75387) { | 383 | if (data->kind == f75387) { |
384 | /* For now, deny dangerous toggling of duty mode */ | ||
385 | if (duty_mode_enabled(data->pwm_enable[nr]) != | ||
386 | duty_mode_enabled(val)) | ||
387 | return -EOPNOTSUPP; | ||
336 | /* clear each fanX_mode bit before setting them properly */ | 388 | /* clear each fanX_mode bit before setting them properly */ |
337 | fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr)); | 389 | fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr)); |
338 | fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr)); | 390 | fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr)); |
@@ -341,19 +393,19 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) | |||
341 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | 393 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); |
342 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | 394 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); |
343 | data->pwm[nr] = 255; | 395 | data->pwm[nr] = 255; |
344 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), | ||
345 | data->pwm[nr]); | ||
346 | break; | 396 | break; |
347 | case 1: /* PWM */ | 397 | case 1: /* PWM */ |
348 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | 398 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); |
349 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | 399 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); |
350 | break; | 400 | break; |
351 | case 2: /* AUTOMATIC*/ | 401 | case 2: /* Automatic, speed mode */ |
352 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | ||
353 | break; | 402 | break; |
354 | case 3: /* fan speed */ | 403 | case 3: /* fan speed */ |
355 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | 404 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); |
356 | break; | 405 | break; |
406 | case 4: /* Automatic, pwm */ | ||
407 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | ||
408 | break; | ||
357 | } | 409 | } |
358 | } else { | 410 | } else { |
359 | /* clear each fanX_mode bit before setting them properly */ | 411 | /* clear each fanX_mode bit before setting them properly */ |
@@ -362,22 +414,24 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) | |||
362 | case 0: /* full speed */ | 414 | case 0: /* full speed */ |
363 | fanmode |= (3 << FAN_CTRL_MODE(nr)); | 415 | fanmode |= (3 << FAN_CTRL_MODE(nr)); |
364 | data->pwm[nr] = 255; | 416 | data->pwm[nr] = 255; |
365 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), | ||
366 | data->pwm[nr]); | ||
367 | break; | 417 | break; |
368 | case 1: /* PWM */ | 418 | case 1: /* PWM */ |
369 | fanmode |= (3 << FAN_CTRL_MODE(nr)); | 419 | fanmode |= (3 << FAN_CTRL_MODE(nr)); |
370 | break; | 420 | break; |
371 | case 2: /* AUTOMATIC*/ | 421 | case 2: /* AUTOMATIC*/ |
372 | fanmode |= (2 << FAN_CTRL_MODE(nr)); | 422 | fanmode |= (1 << FAN_CTRL_MODE(nr)); |
373 | break; | 423 | break; |
374 | case 3: /* fan speed */ | 424 | case 3: /* fan speed */ |
375 | break; | 425 | break; |
426 | case 4: /* Automatic pwm */ | ||
427 | return -EINVAL; | ||
376 | } | 428 | } |
377 | } | 429 | } |
378 | 430 | ||
379 | f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); | 431 | f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); |
380 | data->pwm_enable[nr] = val; | 432 | data->pwm_enable[nr] = val; |
433 | if (val == 0) | ||
434 | f75375_write_pwm(client, nr); | ||
381 | return 0; | 435 | return 0; |
382 | } | 436 | } |
383 | 437 | ||
@@ -723,19 +777,22 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, | |||
723 | if (data->kind == f75387) { | 777 | if (data->kind == f75387) { |
724 | bool manu, duty; | 778 | bool manu, duty; |
725 | 779 | ||
726 | if (!(conf & (1 << F75387_FAN_CTRL_LINEAR(nr)))) | 780 | if (!(mode & (1 << F75387_FAN_CTRL_LINEAR(nr)))) |
727 | data->pwm_mode[nr] = 1; | 781 | data->pwm_mode[nr] = 1; |
728 | 782 | ||
729 | manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1); | 783 | manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1); |
730 | duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1); | 784 | duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1); |
731 | if (manu && duty) | 785 | if (!manu && duty) |
732 | /* speed */ | 786 | /* auto, pwm */ |
787 | data->pwm_enable[nr] = 4; | ||
788 | else if (manu && !duty) | ||
789 | /* manual, speed */ | ||
733 | data->pwm_enable[nr] = 3; | 790 | data->pwm_enable[nr] = 3; |
734 | else if (!manu && duty) | 791 | else if (!manu && !duty) |
735 | /* automatic */ | 792 | /* automatic, speed */ |
736 | data->pwm_enable[nr] = 2; | 793 | data->pwm_enable[nr] = 2; |
737 | else | 794 | else |
738 | /* manual */ | 795 | /* manual, pwm */ |
739 | data->pwm_enable[nr] = 1; | 796 | data->pwm_enable[nr] = 1; |
740 | } else { | 797 | } else { |
741 | if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr)))) | 798 | if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr)))) |
@@ -760,9 +817,11 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, | |||
760 | set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]); | 817 | set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]); |
761 | set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]); | 818 | set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]); |
762 | for (nr = 0; nr < 2; nr++) { | 819 | for (nr = 0; nr < 2; nr++) { |
820 | if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) || | ||
821 | !duty_mode_enabled(f75375s_pdata->pwm_enable[nr])) | ||
822 | continue; | ||
763 | data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255); | 823 | data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255); |
764 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), | 824 | f75375_write_pwm(client, nr); |
765 | data->pwm[nr]); | ||
766 | } | 825 | } |
767 | 826 | ||
768 | } | 827 | } |
@@ -789,7 +848,7 @@ static int f75375_probe(struct i2c_client *client, | |||
789 | if (err) | 848 | if (err) |
790 | goto exit_free; | 849 | goto exit_free; |
791 | 850 | ||
792 | if (data->kind == f75375) { | 851 | if (data->kind != f75373) { |
793 | err = sysfs_chmod_file(&client->dev.kobj, | 852 | err = sysfs_chmod_file(&client->dev.kobj, |
794 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | 853 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, |
795 | S_IRUGO | S_IWUSR); | 854 | S_IRUGO | S_IWUSR); |