On Mon, Nov 20, 2017 at 03:12:04PM +1030, Andrew Jeffery wrote:
> The implementation makes use of the new fan control virtual registers
> exposed by the pmbus core. It mixes use of the default implementations
> with some overrides via the read/write handlers to handle FAN_COMMAND_1
> on the MAX31785, whose definition breaks the value range into various
> control bands dependent on RPM or PWM mode.
> 
> Signed-off-by: Andrew Jeffery <[email protected]>

Applied.

Thanks,
Guenter

> ---
>  Documentation/hwmon/max31785   |   7 ++-
>  drivers/hwmon/pmbus/max31785.c | 138 +++++++++++++++++++++++++++++++++-
>  2 files changed, 144 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785
> index 45fb6093dec2..7b0a0a8cdb6b 100644
> --- a/Documentation/hwmon/max31785
> +++ b/Documentation/hwmon/max31785
> @@ -32,6 +32,7 @@ Sysfs attributes
>  fan[1-4]_alarm               Fan alarm.
>  fan[1-4]_fault               Fan fault.
>  fan[1-4]_input               Fan RPM.
> +fan[1-4]_target              Fan input target
>  
>  in[1-6]_crit         Critical maximum output voltage
>  in[1-6]_crit_alarm   Output voltage critical high alarm
> @@ -44,6 +45,12 @@ in[1-6]_max_alarm  Output voltage high alarm
>  in[1-6]_min          Minimum output voltage
>  in[1-6]_min_alarm    Output voltage low alarm
>  
> +pwm[1-4]             Fan target duty cycle (0..255)
> +pwm[1-4]_enable              0: Full-speed
> +                     1: Manual PWM control
> +                     2: Automatic PWM (tach-feedback RPM fan-control)
> +                     3: Automatic closed-loop (temp-feedback fan-control)
> +
>  temp[1-11]_crit              Critical high temperature
>  temp[1-11]_crit_alarm        Chip temperature critical high alarm
>  temp[1-11]_input     Measured temperature
> diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
> index 9313849d5160..8706a696c89a 100644
> --- a/drivers/hwmon/pmbus/max31785.c
> +++ b/drivers/hwmon/pmbus/max31785.c
> @@ -20,8 +20,136 @@ enum max31785_regs {
>  
>  #define MAX31785_NR_PAGES            23
>  
> +static int max31785_get_pwm(struct i2c_client *client, int page)
> +{
> +     int rv;
> +
> +     rv = pmbus_get_fan_rate_device(client, page, 0, percent);
> +     if (rv < 0)
> +             return rv;
> +     else if (rv >= 0x8000)
> +             return 0;
> +     else if (rv >= 0x2711)
> +             return 0x2710;
> +
> +     return rv;
> +}
> +
> +static int max31785_get_pwm_mode(struct i2c_client *client, int page)
> +{
> +     int config;
> +     int command;
> +
> +     config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
> +     if (config < 0)
> +             return config;
> +
> +     command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
> +     if (command < 0)
> +             return command;
> +
> +     if (config & PB_FAN_1_RPM)
> +             return (command >= 0x8000) ? 3 : 2;
> +
> +     if (command >= 0x8000)
> +             return 3;
> +     else if (command >= 0x2711)
> +             return 0;
> +
> +     return 1;
> +}
> +
> +static int max31785_read_word_data(struct i2c_client *client, int page,
> +                                int reg)
> +{
> +     int rv;
> +
> +     switch (reg) {
> +     case PMBUS_VIRT_PWM_1:
> +             rv = max31785_get_pwm(client, page);
> +             break;
> +     case PMBUS_VIRT_PWM_ENABLE_1:
> +             rv = max31785_get_pwm_mode(client, page);
> +             break;
> +     default:
> +             rv = -ENODATA;
> +             break;
> +     }
> +
> +     return rv;
> +}
> +
> +static inline u32 max31785_scale_pwm(u32 sensor_val)
> +{
> +     /*
> +      * The datasheet describes the accepted value range for manual PWM as
> +      * [0, 0x2710], while the hwmon pwmX sysfs interface accepts values in
> +      * [0, 255]. The MAX31785 uses DIRECT mode to scale the FAN_COMMAND
> +      * registers and in PWM mode the coefficients are m=1, b=0, R=2. The
> +      * important observation here is that 0x2710 == 10000 == 100 * 100.
> +      *
> +      * R=2 (== 10^2 == 100) accounts for scaling the value provided at the
> +      * sysfs interface into the required hardware resolution, but it does
> +      * not yet yield a value that we can write to the device (this initial
> +      * scaling is handled by pmbus_data2reg()). Multiplying by 100 below
> +      * translates the parameter value into the percentage units required by
> +      * PMBus, and then we scale back by 255 as required by the hwmon pwmX
> +      * interface to yield the percentage value at the appropriate
> +      * resolution for hardware.
> +      */
> +     return (sensor_val * 100) / 255;
> +}
> +
> +static int max31785_pwm_enable(struct i2c_client *client, int page,
> +                                 u16 word)
> +{
> +     int config = 0;
> +     int rate;
> +
> +     switch (word) {
> +     case 0:
> +             rate = 0x7fff;
> +             break;
> +     case 1:
> +             rate = pmbus_get_fan_rate_cached(client, page, 0, percent);
> +             if (rate < 0)
> +                     return rate;
> +             rate = max31785_scale_pwm(rate);
> +             break;
> +     case 2:
> +             config = PB_FAN_1_RPM;
> +             rate = pmbus_get_fan_rate_cached(client, page, 0, rpm);
> +             if (rate < 0)
> +                     return rate;
> +             break;
> +     case 3:
> +             rate = 0xffff;
> +             break;
> +     default:
> +             return -EINVAL;
> +     }
> +
> +     return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate);
> +}
> +
> +static int max31785_write_word_data(struct i2c_client *client, int page,
> +                                 int reg, u16 word)
> +{
> +     switch (reg) {
> +     case PMBUS_VIRT_PWM_1:
> +             return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
> +                                     max31785_scale_pwm(word));
> +     case PMBUS_VIRT_PWM_ENABLE_1:
> +             return max31785_pwm_enable(client, page, word);
> +     default:
> +             break;
> +     }
> +
> +     return -ENODATA;
> +}
> +
>  #define MAX31785_FAN_FUNCS \
> -     (PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12)
> +     (PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_PWM12)
>  
>  #define MAX31785_TEMP_FUNCS \
>       (PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
> @@ -32,11 +160,19 @@ enum max31785_regs {
>  static const struct pmbus_driver_info max31785_info = {
>       .pages = MAX31785_NR_PAGES,
>  
> +     .write_word_data = max31785_write_word_data,
> +     .read_word_data = max31785_read_word_data,
> +
>       /* RPM */
>       .format[PSC_FAN] = direct,
>       .m[PSC_FAN] = 1,
>       .b[PSC_FAN] = 0,
>       .R[PSC_FAN] = 0,
> +     /* PWM */
> +     .format[PSC_PWM] = direct,
> +     .m[PSC_PWM] = 1,
> +     .b[PSC_PWM] = 0,
> +     .R[PSC_PWM] = 2,
>       .func[0] = MAX31785_FAN_FUNCS,
>       .func[1] = MAX31785_FAN_FUNCS,
>       .func[2] = MAX31785_FAN_FUNCS,

Reply via email to