diff --git a/drivers/hwmon/tacho-phytium.c b/drivers/hwmon/tacho-phytium.c index 44bbb06b49df75bb1864d2c7a2b897113715f8f0..92a6637a1b8622947f6408f3fa18b4e37cef95bd 100644 --- a/drivers/hwmon/tacho-phytium.c +++ b/drivers/hwmon/tacho-phytium.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -58,6 +59,8 @@ #define TIMER_INT_CLR_MASK GENMASK(5, 0) #define TIMER_TACHO_DEFAULT_FREQ 0x2FAF080 +#define MAX_PWM 255 + #define TACHO_DRIVER_VERSION "1.1.1" enum tacho_modes { @@ -71,9 +74,17 @@ falling_edge, double_edge, }; +struct pwm_data { + struct pwm_device *pwm; + struct mutex pwm_lock; + u8 pwm_value; + bool pwm_present; +}; + struct phytium_tacho { struct device *dev; struct device *hwmon; + struct pwm_data pwmdata; void __iomem *base; struct clk *clk; u32 freq; @@ -181,8 +192,80 @@ static const struct attribute_group tacho_group = { .is_visible = tacho_dev_is_visible, }; +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct phytium_tacho *priv = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", priv->pwmdata.pwm_value); +} + +static int __set_pwm(struct phytium_tacho *priv, unsigned long pwm) +{ + unsigned long period; + int ret = 0; + struct pwm_state state = {}; + mutex_lock(&priv->pwmdata.pwm_lock); + + pwm_init_state(priv->pwmdata.pwm, &state); + period = priv->pwmdata.pwm->args.period; + state.duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + state.enabled = pwm ? true : false; + ret = pwm_apply_state(priv->pwmdata.pwm, &state); + mutex_unlock(&priv->pwmdata.pwm_lock); + return ret; +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct phytium_tacho *priv = dev_get_drvdata(dev); + long fan_ctrl; + + ret = kstrtol(buf, 10, &fan_ctrl); + if (ret != 0) + return ret; + + if (fan_ctrl < 0 || fan_ctrl > MAX_PWM) + return -EINVAL; + + if (priv->pwmdata.pwm_value == fan_ctrl) + return count; + + ret = __set_pwm(priv, fan_ctrl); + if (!ret) + priv->pwmdata.pwm_value = fan_ctrl; + + return count; +} + +static SENSOR_DEVICE_ATTR(pwm1, 0644, show_pwm, set_pwm, 0); + +static struct attribute *pwm_attrs[] = { + &sensor_dev_attr_pwm1.dev_attr.attr, + NULL, +}; + +static umode_t pwm_is_visible(struct kobject *kobj, struct attribute *a, + int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct phytium_tacho *priv = dev_get_drvdata(dev); + + if (!priv->pwmdata.pwm_present) + return 0; + return a->mode; +} + +static const struct attribute_group pwm_group = { + .attrs = pwm_attrs, + .is_visible = pwm_is_visible, +}; + static const struct attribute_group *tacho_groups[] = { &tacho_group, + &pwm_group, NULL }; @@ -291,6 +374,45 @@ static void phytium_tacho_get_of_data(struct phytium_tacho *tacho) tacho->ppr = phytium_tacho_get_ppr(tacho); } +static int phytium_tacho_create_pwm_port(struct phytium_tacho *tacho) +{ + struct pwm_state state = {}; + int ret; + tacho->pwmdata.pwm_present = true; + tacho->pwmdata.pwm_value = MAX_PWM; + + /* Set duty cycle to maximum allowed and enable PWM output */ + pwm_init_state(tacho->pwmdata.pwm, &state); + state.duty_cycle = tacho->pwmdata.pwm->args.period - 1; + state.enabled = true; + + ret = pwm_apply_state(tacho->pwmdata.pwm, &state); + if (ret) + dev_err(tacho->dev, "Failed to configure PWM node\n"); + return ret; +} + +static void phytium_tacho_create_pwm(struct phytium_tacho *tacho) +{ + u32 ret,len; + struct fwnode_handle *fwn = tacho->dev->fwnode; + + /* support without pwms property */ + if (fwnode_property_present(fwn, "pwms")) { + tacho->pwmdata.pwm = devm_fwnode_pwm_get(tacho->dev, fwn, NULL); + if (IS_ERR(tacho->pwmdata.pwm)) { + dev_warn(tacho->dev, "Could not get PWM node configured\n"); + } else { + ret = phytium_tacho_create_pwm_port(tacho); + if (ret) + dev_warn(tacho->dev, + "Could not creat PWM (%x) node\n", ret); + } + } else { + dev_info(tacho->dev, "No PWM node configured\n"); + } +} + static int phytium_tacho_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -345,6 +467,8 @@ static int phytium_tacho_probe(struct platform_device *pdev) phytium_tacho_init(tacho); + phytium_tacho_create_pwm(tacho); + if (tacho->work_mode == tacho_mode) tacho->hwmon = devm_hwmon_device_register_with_groups(dev, "phytium_tacho", diff --git a/drivers/pwm/pwm-phytium.c b/drivers/pwm/pwm-phytium.c index 742cbfd88b6fb1de62f6d190e7a33562205f8589..395f2d3a627d802ce0fb90d61607bf4055ce7bdd 100644 --- a/drivers/pwm/pwm-phytium.c +++ b/drivers/pwm/pwm-phytium.c @@ -296,13 +296,6 @@ static int pwm_phytium_db_init(struct pwm_chip *chip, struct pwm_device *pwm) return 0; } -static int __pwm_phytium_config(struct pwm_chip *chip, struct pwm_device *pwm) -{ - pwm_phytium_init(chip, pwm, 0); - pwm_phytium_init(chip, pwm, 1); - return 0; -} - static int pwm_phytium_set_polarity(struct pwm_chip *chip, enum pwm_polarity polarity, int n) { struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); @@ -336,7 +329,7 @@ static int pwm_phytium_apply(struct pwm_chip *chip, struct pwm_device *pwm, n = pwm->hwpwm & BIT(0); - if ((state->polarity != cstate.polarity) && !state->enabled) + if ((state->polarity != cstate.polarity) && !cstate.enabled) pwm_phytium_set_polarity(chip, state->polarity, n); if (state->enabled && !cstate.enabled) @@ -374,7 +367,7 @@ static int pwm_phytium_request(struct pwm_chip *chip, struct pwm_device *pwm) return -ENOMEM; pwm_set_chip_data(pwm, our_chan); - __pwm_phytium_config(&our_chip->chip, our_chip->chip.pwms); + pwm_phytium_init(&our_chip->chip, pwm, pwm->hwpwm); return 0; } @@ -529,8 +522,8 @@ static int pwm_phytium_pm_init(struct phytium_pwm_chip *priv) { int i; - __pwm_phytium_config(&priv->chip, priv->chip.pwms); for (i = 0; i < priv->chip.npwm; i++) { + pwm_phytium_init(&priv->chip, &priv->chip.pwms[i], i); writel(priv->state_pm[i].period, priv->base + PWM_N(i) + REG_TPERIOD); if ((priv->db_init == 1) && (i == 0)) pwm_phytium_db_init(&priv->chip, priv->chip.pwms);