Lines Matching +full:clk +full:- +full:pwm

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2017-2025 Loongson Technology Corporation Limited.
5 * Loongson PWM driver
7 * For Loongson's PWM IP block documentation please refer Chapter 11 of
8 …* Reference Manual: https://loongson.github.io/LoongArch-Documentation/Loongson-7A1000-usermanual-
15 * - If both DUTY and PERIOD are set to 0, the output is a constant low signal.
16 * - When disabled the output is driven to 0 independent of the configured
18 * - If the register is reconfigured while PWM is running, it does not complete
20 * - Disabling the PWM stops the output immediately (without waiting for current
25 #include <linux/clk.h>
32 #include <linux/pwm.h>
35 /* Loongson PWM registers */
48 #define LOONGSON_PWM_CTRL_REG_INVERT BIT(9) /* Output flip-flop Enable Bit */
49 #define LOONGSON_PWM_CTRL_REG_DZONE BIT(10) /* Anti-dead Zone Enable Bit */
51 /* default input clk frequency for the ACPI case */
55 struct clk *clk; member
67 return readl(ddata->base + offset); in pwm_loongson_readl()
73 writel(val, ddata->base + offset); in pwm_loongson_writel()
76 static int pwm_loongson_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, in pwm_loongson_set_polarity() argument
85 /* Duty cycle defines LOW period of PWM */ in pwm_loongson_set_polarity()
88 /* Duty cycle defines HIGH period of PWM */ in pwm_loongson_set_polarity()
96 static void pwm_loongson_disable(struct pwm_chip *chip, struct pwm_device *pwm) in pwm_loongson_disable() argument
106 static int pwm_loongson_enable(struct pwm_chip *chip, struct pwm_device *pwm) in pwm_loongson_enable() argument
118 static int pwm_loongson_config(struct pwm_chip *chip, struct pwm_device *pwm, in pwm_loongson_config() argument
124 /* duty = duty_ns * ddata->clk_rate / NSEC_PER_SEC */ in pwm_loongson_config()
125 duty = mul_u64_u64_div_u64(duty_ns, ddata->clk_rate, NSEC_PER_SEC); in pwm_loongson_config()
129 /* period = period_ns * ddata->clk_rate / NSEC_PER_SEC */ in pwm_loongson_config()
130 period = mul_u64_u64_div_u64(period_ns, ddata->clk_rate, NSEC_PER_SEC); in pwm_loongson_config()
140 static int pwm_loongson_apply(struct pwm_chip *chip, struct pwm_device *pwm, in pwm_loongson_apply() argument
144 bool enabled = pwm->state.enabled; in pwm_loongson_apply()
146 if (!state->enabled) { in pwm_loongson_apply()
148 pwm_loongson_disable(chip, pwm); in pwm_loongson_apply()
152 ret = pwm_loongson_set_polarity(chip, pwm, state->polarity); in pwm_loongson_apply()
156 ret = pwm_loongson_config(chip, pwm, state->duty_cycle, state->period); in pwm_loongson_apply()
160 if (!enabled && state->enabled) in pwm_loongson_apply()
161 ret = pwm_loongson_enable(chip, pwm); in pwm_loongson_apply()
166 static int pwm_loongson_get_state(struct pwm_chip *chip, struct pwm_device *pwm, in pwm_loongson_get_state() argument
177 state->duty_cycle = DIV64_U64_ROUND_UP((u64)duty * NSEC_PER_SEC, ddata->clk_rate); in pwm_loongson_get_state()
178 state->period = DIV64_U64_ROUND_UP((u64)period * NSEC_PER_SEC, ddata->clk_rate); in pwm_loongson_get_state()
179 state->polarity = (ctrl & LOONGSON_PWM_CTRL_REG_INVERT) ? PWM_POLARITY_INVERSED : in pwm_loongson_get_state()
181 state->enabled = (ctrl & LOONGSON_PWM_CTRL_REG_EN) ? true : false; in pwm_loongson_get_state()
196 struct device *dev = &pdev->dev; in pwm_loongson_probe()
203 ddata->base = devm_platform_ioremap_resource(pdev, 0); in pwm_loongson_probe()
204 if (IS_ERR(ddata->base)) in pwm_loongson_probe()
205 return PTR_ERR(ddata->base); in pwm_loongson_probe()
207 ddata->clk = devm_clk_get_optional_enabled(dev, NULL); in pwm_loongson_probe()
208 if (IS_ERR(ddata->clk)) in pwm_loongson_probe()
209 return dev_err_probe(dev, PTR_ERR(ddata->clk), in pwm_loongson_probe()
210 "Failed to get pwm clock\n"); in pwm_loongson_probe()
211 if (ddata->clk) { in pwm_loongson_probe()
212 ret = devm_clk_rate_exclusive_get(dev, ddata->clk); in pwm_loongson_probe()
217 ddata->clk_rate = clk_get_rate(ddata->clk); in pwm_loongson_probe()
218 if (!ddata->clk_rate) in pwm_loongson_probe()
219 return dev_err_probe(dev, -EINVAL, in pwm_loongson_probe()
222 ddata->clk_rate = LOONGSON_PWM_FREQ_DEFAULT; in pwm_loongson_probe()
226 if (ddata->clk_rate > NSEC_PER_SEC) in pwm_loongson_probe()
227 return dev_err_probe(dev, -EINVAL, "PWM clock out of range\n"); in pwm_loongson_probe()
229 chip->ops = &pwm_loongson_ops; in pwm_loongson_probe()
230 chip->atomic = true; in pwm_loongson_probe()
235 return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); in pwm_loongson_probe()
244 struct pwm_device *pwm = &chip->pwms[0]; in pwm_loongson_suspend() local
246 if (pwm->state.enabled) in pwm_loongson_suspend()
247 return -EBUSY; in pwm_loongson_suspend()
249 clk_disable_unprepare(ddata->clk); in pwm_loongson_suspend()
259 return clk_prepare_enable(ddata->clk); in pwm_loongson_resume()
266 { .compatible = "loongson,ls7a-pwm" },
280 .name = "loongson-pwm",
288 MODULE_DESCRIPTION("Loongson PWM driver");