Lines Matching +full:pwm +full:- +full:active +full:- +full:state

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * PWM/TACH controller driver for Aspeed ast2600 SoCs.
9 * Q := (DIV_L + 1) << DIV_H / input-clk
10 * The length of a PWM period is (DUTY_CYCLE_PERIOD + 1) * Q.
15 * period the output is active until DUTY_CYCLE_FALLING_POINT * Q. Note
17 * always active.
20 * PIN_ENABLE: When it is unset the pwm controller will emit inactive level to the external.
21 * Use to determine whether the PWM channel is enabled or disabled
22 * CLK_ENABLE: When it is unset the pwm controller will assert the duty counter reset and
23 * emit inactive level to the PIN_ENABLE mux after that the driver can still change the pwm period
31 * - Enabled changing when the duty_cycle bigger than 0% and less than 100%.
32 * - Polarity changing when the duty_cycle bigger than 0% and less than 100%.
35 * - When changing both duty cycle and period, we cannot prevent in
38 * - Disabling the PWM doesn't complete the current period.
41 * - When only changing one of duty cycle or period, our pwm controller will not
42 * generate the glitch, the configure will change at next cycle of pwm.
58 #include <linux/pwm.h>
62 /* The channel number of Aspeed pwm controller */
64 /* PWM Control Register */
77 /* PWM Duty Cycle Register */
84 /* PWM fixed value */
150 static int aspeed_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, in aspeed_pwm_get_state() argument
151 struct pwm_state *state) in aspeed_pwm_get_state() argument
154 u32 hwpwm = pwm->hwpwm; in aspeed_pwm_get_state()
159 val = readl(priv->base + PWM_ASPEED_CTRL(hwpwm)); in aspeed_pwm_get_state()
165 val = readl(priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); in aspeed_pwm_get_state()
174 state->period = DIV_ROUND_UP_ULL(dividend, priv->clk_rate); in aspeed_pwm_get_state()
179 state->duty_cycle = DIV_ROUND_UP_ULL(dividend, priv->clk_rate); in aspeed_pwm_get_state()
181 state->duty_cycle = clk_en ? state->period : 0; in aspeed_pwm_get_state()
183 state->polarity = polarity ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; in aspeed_pwm_get_state()
184 state->enabled = pin_en; in aspeed_pwm_get_state()
188 static int aspeed_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, in aspeed_pwm_apply() argument
189 const struct pwm_state *state) in aspeed_pwm_apply() argument
192 u32 hwpwm = pwm->hwpwm, duty_pt, val; in aspeed_pwm_apply()
196 expect_period = div64_u64(ULLONG_MAX, (u64)priv->clk_rate); in aspeed_pwm_apply()
197 expect_period = min(expect_period, state->period); in aspeed_pwm_apply()
198 dev_dbg(chip->dev, "expect period: %lldns, duty_cycle: %lldns", in aspeed_pwm_apply()
199 expect_period, state->duty_cycle); in aspeed_pwm_apply()
206 div_h = order_base_2(DIV64_U64_ROUND_UP(priv->clk_rate * expect_period, divisor)); in aspeed_pwm_apply()
211 div_l = div64_u64(priv->clk_rate * expect_period, divisor); in aspeed_pwm_apply()
214 return -ERANGE; in aspeed_pwm_apply()
216 div_l -= 1; in aspeed_pwm_apply()
221 dev_dbg(chip->dev, "clk source: %ld div_h %lld, div_l : %lld\n", in aspeed_pwm_apply()
222 priv->clk_rate, div_h, div_l); in aspeed_pwm_apply()
224 duty_pt = div64_u64(state->duty_cycle * priv->clk_rate, in aspeed_pwm_apply()
226 dev_dbg(chip->dev, "duty_cycle = %lld, duty_pt = %d\n", in aspeed_pwm_apply()
227 state->duty_cycle, duty_pt); in aspeed_pwm_apply()
231 * fine-grained resolution for duty_cycle at the expense of a in aspeed_pwm_apply()
234 val = readl(priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); in aspeed_pwm_apply()
238 writel(val, priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); in aspeed_pwm_apply()
247 val = readl(priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); in aspeed_pwm_apply()
251 writel(val, priv->base + PWM_ASPEED_DUTY_CYCLE(hwpwm)); in aspeed_pwm_apply()
254 val = readl(priv->base + PWM_ASPEED_CTRL(hwpwm)); in aspeed_pwm_apply()
260 FIELD_PREP(PWM_ASPEED_CTRL_PIN_ENABLE, state->enabled) | in aspeed_pwm_apply()
262 FIELD_PREP(PWM_ASPEED_CTRL_INVERSE, state->polarity); in aspeed_pwm_apply()
263 writel(val, priv->base + PWM_ASPEED_CTRL(hwpwm)); in aspeed_pwm_apply()
277 writel(readl(priv->base + TACH_ASPEED_CTRL(tach_ch)) | in aspeed_tach_ch_enable()
279 priv->base + TACH_ASPEED_CTRL(tach_ch)); in aspeed_tach_ch_enable()
281 writel(readl(priv->base + TACH_ASPEED_CTRL(tach_ch)) & in aspeed_tach_ch_enable()
283 priv->base + TACH_ASPEED_CTRL(tach_ch)); in aspeed_tach_ch_enable()
291 tach_div = tach_val * priv->tach_divisor * DEFAULT_FAN_PULSE_PR; in aspeed_tach_val_to_rpm()
293 dev_dbg(priv->dev, "clk %ld, tach_val %d , tach_div %d\n", in aspeed_tach_val_to_rpm()
294 priv->clk_rate, tach_val, tach_div); in aspeed_tach_val_to_rpm()
296 rpm = (u64)priv->clk_rate * 60; in aspeed_tach_val_to_rpm()
307 val = readl(priv->base + TACH_ASPEED_STS(fan_tach_ch)); in aspeed_get_fan_tach_ch_rpm()
327 reg_val = readl(priv->base + TACH_ASPEED_CTRL(channel)); in aspeed_tach_hwmon_read()
332 return -EOPNOTSUPP; in aspeed_tach_hwmon_read()
348 return -EINVAL; in aspeed_tach_hwmon_write()
349 priv->tach_divisor = val; in aspeed_tach_hwmon_write()
350 reg_val = readl(priv->base + TACH_ASPEED_CTRL(channel)); in aspeed_tach_hwmon_write()
353 DIV_TO_REG(priv->tach_divisor)); in aspeed_tach_hwmon_write()
354 writel(reg_val, priv->base + TACH_ASPEED_CTRL(channel)); in aspeed_tach_hwmon_write()
357 return -EOPNOTSUPP; in aspeed_tach_hwmon_write()
369 if (!priv->tach_present[channel]) in aspeed_tach_dev_is_visible()
410 priv->tach_present[ch] = true; in aspeed_present_fan_tach()
411 priv->tach_divisor = DEFAULT_TACH_DIV; in aspeed_present_fan_tach()
413 val = readl(priv->base + TACH_ASPEED_CTRL(ch)); in aspeed_present_fan_tach()
420 DIV_TO_REG(priv->tach_divisor)); in aspeed_present_fan_tach()
421 writel(val, priv->base + TACH_ASPEED_CTRL(ch)); in aspeed_present_fan_tach()
434 count = of_property_count_u8_elems(child, "tach-ch"); in aspeed_create_fan_monitor()
436 return -EINVAL; in aspeed_create_fan_monitor()
439 return -ENOMEM; in aspeed_create_fan_monitor()
440 ret = of_property_read_u8_array(child, "tach-ch", tach_ch, count); in aspeed_create_fan_monitor()
458 struct device *dev = &pdev->dev, *hwmon; in aspeed_pwm_tach_probe()
465 return -ENOMEM; in aspeed_pwm_tach_probe()
466 priv->dev = dev; in aspeed_pwm_tach_probe()
467 priv->base = devm_platform_ioremap_resource(pdev, 0); in aspeed_pwm_tach_probe()
468 if (IS_ERR(priv->base)) in aspeed_pwm_tach_probe()
469 return PTR_ERR(priv->base); in aspeed_pwm_tach_probe()
471 priv->clk = devm_clk_get_enabled(dev, NULL); in aspeed_pwm_tach_probe()
472 if (IS_ERR(priv->clk)) in aspeed_pwm_tach_probe()
473 return dev_err_probe(dev, PTR_ERR(priv->clk), in aspeed_pwm_tach_probe()
475 priv->clk_rate = clk_get_rate(priv->clk); in aspeed_pwm_tach_probe()
476 priv->reset = devm_reset_control_get_exclusive(dev, NULL); in aspeed_pwm_tach_probe()
477 if (IS_ERR(priv->reset)) in aspeed_pwm_tach_probe()
478 return dev_err_probe(dev, PTR_ERR(priv->reset), in aspeed_pwm_tach_probe()
481 ret = reset_control_deassert(priv->reset); in aspeed_pwm_tach_probe()
486 priv->reset); in aspeed_pwm_tach_probe()
490 priv->chip.dev = dev; in aspeed_pwm_tach_probe()
491 priv->chip.ops = &aspeed_pwm_ops; in aspeed_pwm_tach_probe()
492 priv->chip.npwm = PWM_ASPEED_NR_PWMS; in aspeed_pwm_tach_probe()
494 ret = devm_pwmchip_add(dev, &priv->chip); in aspeed_pwm_tach_probe()
496 return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); in aspeed_pwm_tach_probe()
498 for_each_child_of_node(dev->of_node, child) { in aspeed_pwm_tach_probe()
514 of_platform_populate(dev->of_node, NULL, NULL, dev); in aspeed_pwm_tach_probe()
523 reset_control_assert(priv->reset); in aspeed_pwm_tach_remove()
530 .compatible = "aspeed,ast2600-pwm-tach",
540 .name = "aspeed-g6-pwm-tach",
548 MODULE_DESCRIPTION("Aspeed ast2600 PWM and Fan Tach device driver");