Utilise pwm subsystem for fan pwm handling Signed-off-by: Naresh Solanki <naresh.solanki@xxxxxxxxxxxxx> --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/max6639.c | 200 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 191 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 257ec5360e35..c9cc74f8c807 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1224,6 +1224,7 @@ config SENSORS_MAX6639 tristate "Maxim MAX6639 sensor chip" depends on I2C select REGMAP_I2C + depends on PWM help If you say yes here you get support for the MAX6639 sensor chips. diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 1af93fc53cb5..f37fdd161154 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -20,6 +20,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/platform_data/max6639.h> +#include <linux/pwm.h> #include <linux/regmap.h> /* Addresses to scan */ @@ -55,6 +56,9 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; #define MAX6639_GCONFIG_PWM_FREQ_HI 0x08 #define MAX6639_FAN_CONFIG1_PWM 0x80 +#define MAX6639_REG_FAN_CONFIG2a_PWM_POL 0x02 +#define MAX6639_FAN_CONFIG3_FREQ_MASK 0x03 +#define MAX6639_REG_TARGTDUTY_SLOT 120 #define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED 0x40 @@ -62,6 +66,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 }; +/* Supported PWM frequency */ +static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500, + 25000 }; + #define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \ 0 : (rpm_ranges[rpm_range] * 30) / (val)) #define TEMP_LIMIT_TO_REG(val) clamp_val((val) / 1000, 0, 255) @@ -93,6 +101,9 @@ struct max6639_data { /* Optional regulator for FAN supply */ struct regulator *reg; + /* max6639 pwm chip */ + struct pwm_chip chip; + struct pwm_device *pwmd[MAX6639_NDEV]; /* max6639 has two pwm device */ }; static struct max6639_data *max6639_update_device(struct device *dev) @@ -271,8 +282,11 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *dev_attr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); struct max6639_data *data = dev_get_drvdata(dev); + struct pwm_state state; + + pwm_get_state(data->pwmd[attr->index], &state); - return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120); + return sprintf(buf, "%d\n", pwm_get_relative_duty_cycle(&state, 255)); } static ssize_t pwm_store(struct device *dev, @@ -281,6 +295,7 @@ static ssize_t pwm_store(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); struct max6639_data *data = dev_get_drvdata(dev); + struct pwm_state state; unsigned long val; int res; @@ -290,10 +305,10 @@ static ssize_t pwm_store(struct device *dev, val = clamp_val(val, 0, 255); - mutex_lock(&data->update_lock); - data->pwm[attr->index] = (u8)(val * 120 / 255); - regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(attr->index), data->pwm[attr->index]); - mutex_unlock(&data->update_lock); + pwm_get_state(data->pwmd[attr->index], &state); + pwm_set_relative_duty_cycle(&state, val, 255); + pwm_apply_state(data->pwmd[attr->index], &state); + return count; } @@ -373,6 +388,158 @@ static struct attribute *max6639_attrs[] = { }; ATTRIBUTE_GROUPS(max6639); +static struct max6639_data *to_max6639_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct max6639_data, chip); +} + +static int max6639_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct max6639_data *data = to_max6639_pwm(chip); + int value, i = pwm->hwpwm, x, err; + unsigned int freq; + + mutex_lock(&data->update_lock); + + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG1(i), &value); + if (err < 0) + goto abort; + + if (value & MAX6639_FAN_CONFIG1_PWM) { + state->enabled = true; + + /* Determine frequency from respective registers */ + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG3(i), &value); + if (err < 0) + goto abort; + x = value & MAX6639_FAN_CONFIG3_FREQ_MASK; + + err = regmap_read(data->regmap, MAX6639_REG_GCONFIG, &value); + if (err < 0) + goto abort; + if (value & MAX6639_GCONFIG_PWM_FREQ_HI) + x |= 0x4; + x &= 0x7; + freq = freq_table[x]; + + state->period = DIV_ROUND_UP(NSEC_PER_SEC, freq); + + err = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(i), &value); + if (err < 0) + goto abort; + /* max6639 supports 120 slots only */ + state->duty_cycle = mul_u64_u32_div(state->period, value, 120); + + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), &value); + if (err < 0) + goto abort; + value &= MAX6639_REG_FAN_CONFIG2a_PWM_POL; + state->polarity = (value != 0); + } else { + state->enabled = false; + } + +abort: + mutex_unlock(&data->update_lock); + return value; +} + +static int max6639_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct max6639_data *data = to_max6639_pwm(chip); + int value, i = pwm->hwpwm, x, err; + unsigned int freq; + struct pwm_state cstate; + + cstate = pwm->state; + + mutex_lock(&data->update_lock); + + if (state->period != cstate.period) { + /* Configure frequency */ + freq = DIV_ROUND_UP_ULL(NSEC_PER_SEC, state->period); + + /* Chip supports limited number of frequency */ + for (x = 0; x < sizeof(freq_table); x++) + if (freq <= freq_table[x]) + break; + + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG3(i), &value); + if (err < 0) + goto abort; + + value &= ~MAX6639_FAN_CONFIG3_FREQ_MASK; + value |= (x & MAX6639_FAN_CONFIG3_FREQ_MASK); + err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i), value); + if (err < 0) + goto abort; + + err = regmap_read(data->regmap, MAX6639_REG_GCONFIG, &value); + if (err < 0) + goto abort; + + if (x >> 2) + value &= ~MAX6639_GCONFIG_PWM_FREQ_HI; + else + value |= MAX6639_GCONFIG_PWM_FREQ_HI; + err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, value); + if (err < 0) + goto abort; + } + + /* Configure dutycycle */ + if (state->duty_cycle != cstate.duty_cycle || + state->period != cstate.period) { + value = DIV_ROUND_DOWN_ULL(state->duty_cycle * MAX6639_REG_TARGTDUTY_SLOT, + state->period); + err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), value); + if (err < 0) + goto abort; + } + + /* Configure polarity */ + if (state->polarity != cstate.polarity) { + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), &value); + if (err < 0) + goto abort; + if (state->polarity == PWM_POLARITY_NORMAL) + value |= MAX6639_REG_FAN_CONFIG2a_PWM_POL; + else + value &= ~MAX6639_REG_FAN_CONFIG2a_PWM_POL; + err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), value); + if (err < 0) + goto abort; + } + + if (state->enabled != cstate.enabled) { + err = regmap_read(data->regmap, MAX6639_REG_FAN_CONFIG1(i), &value); + if (err < 0) + goto abort; + if (state->enabled) + value |= MAX6639_FAN_CONFIG1_PWM; + else + value &= ~MAX6639_FAN_CONFIG1_PWM; + + err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i), value); + if (err < 0) + goto abort; + } + value = 0; + +abort: + mutex_unlock(&data->update_lock); + + return err; +} + +static const struct pwm_ops max6639_pwm_ops = { + .apply = max6639_pwm_apply, + .get_state = max6639_pwm_get_state, +}; + /* * returns respective index in rpm_ranges table * 1 by default on invalid range @@ -396,6 +563,7 @@ static int max6639_init_client(struct i2c_client *client, dev_get_platdata(&client->dev); int i; int rpm_range = 1; /* default: 4000 RPM */ + struct pwm_state state; int err; /* Reset chip to default values, see below for GCONFIG setup */ @@ -459,11 +627,15 @@ static int max6639_init_client(struct i2c_client *client, if (err) goto exit; - /* PWM 120/120 (i.e. 100%) */ - data->pwm[i] = 120; - err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), data->pwm[i]); - if (err) - goto exit; + dev_dbg(&client->dev, "Using chip default PWM"); + data->pwmd[i] = pwm_request_from_chip(&data->chip, i, NULL); + if (IS_ERR(data->pwmd[i])) + return PTR_ERR(data->pwmd[i]); + pwm_get_state(data->pwmd[i], &state); + state.period = DIV_ROUND_UP(NSEC_PER_SEC, 25000); + state.polarity = PWM_POLARITY_NORMAL; + pwm_set_relative_duty_cycle(&state, 0, 255); + pwm_apply_state(data->pwmd[i], &state); } /* Start monitoring */ err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, @@ -540,6 +712,14 @@ static int max6639_probe(struct i2c_client *client) PTR_ERR(data->regmap), "regmap initialization failed\n"); + /* Add PWM controller of max6639 */ + data->chip.dev = dev; + data->chip.ops = &max6639_pwm_ops; + data->chip.npwm = MAX6639_NDEV; + err = devm_pwmchip_add(dev, &data->chip); + if (err < 0) + return dev_err_probe(dev, err, "failed to add PWM chip\n"); + data->reg = devm_regulator_get_optional(dev, "fan"); if (IS_ERR(data->reg)) { if (PTR_ERR(data->reg) != -ENODEV) -- 2.42.0