Merge tag 'mm-hotfixes-stable-2024-11-16-15-33' of git://git.kernel.org/pub/scm/linux...
[linux.git] / drivers / pwm / pwm-dwc-core.c
blobc8425493b95d855a7562406501b7c803ef481b22
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * DesignWare PWM Controller driver core
5 * Copyright (C) 2018-2020 Intel Corporation
7 * Author: Felipe Balbi (Intel)
8 * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
9 * Author: Raymond Tan <raymond.tan@intel.com>
12 #define DEFAULT_SYMBOL_NAMESPACE dwc_pwm
14 #include <linux/bitops.h>
15 #include <linux/export.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/pci.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/pwm.h>
22 #include "pwm-dwc.h"
24 static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
26 u32 reg;
28 reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm));
30 if (enabled)
31 reg |= DWC_TIM_CTRL_EN;
32 else
33 reg &= ~DWC_TIM_CTRL_EN;
35 dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm));
38 static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
39 struct pwm_device *pwm,
40 const struct pwm_state *state)
42 u64 tmp;
43 u32 ctrl;
44 u32 high;
45 u32 low;
48 * Calculate width of low and high period in terms of input clock
49 * periods and check are the result within HW limits between 1 and
50 * 2^32 periods.
52 tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
53 if (tmp < 1 || tmp > (1ULL << 32))
54 return -ERANGE;
55 low = tmp - 1;
57 tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
58 dwc->clk_ns);
59 if (tmp < 1 || tmp > (1ULL << 32))
60 return -ERANGE;
61 high = tmp - 1;
64 * Specification says timer usage flow is to disable timer, then
65 * program it followed by enable. It also says Load Count is loaded
66 * into timer after it is enabled - either after a disable or
67 * a reset. Based on measurements it happens also without disable
68 * whenever Load Count is updated. But follow the specification.
70 __dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
73 * Write Load Count and Load Count 2 registers. Former defines the
74 * width of low period and latter the width of high period in terms
75 * multiple of input clock periods:
76 * Width = ((Count + 1) * input clock period).
78 dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm));
79 dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm));
82 * Set user-defined mode, timer reloads from Load Count registers
83 * when it counts down to 0.
84 * Set PWM mode, it makes output to toggle and width of low and high
85 * periods are set by Load Count registers.
87 ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM;
88 dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm));
91 * Enable timer. Output starts from low period.
93 __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled);
95 return 0;
98 static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
99 const struct pwm_state *state)
101 struct dwc_pwm *dwc = to_dwc_pwm(chip);
103 if (state->polarity != PWM_POLARITY_INVERSED)
104 return -EINVAL;
106 if (state->enabled) {
107 if (!pwm->state.enabled)
108 pm_runtime_get_sync(pwmchip_parent(chip));
109 return __dwc_pwm_configure_timer(dwc, pwm, state);
110 } else {
111 if (pwm->state.enabled) {
112 __dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
113 pm_runtime_put_sync(pwmchip_parent(chip));
117 return 0;
120 static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
121 struct pwm_state *state)
123 struct dwc_pwm *dwc = to_dwc_pwm(chip);
124 u64 duty, period;
125 u32 ctrl, ld, ld2;
127 pm_runtime_get_sync(pwmchip_parent(chip));
129 ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm));
130 ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
131 ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
133 state->enabled = !!(ctrl & DWC_TIM_CTRL_EN);
136 * If we're not in PWM, technically the output is a 50-50
137 * based on the timer load-count only.
139 if (ctrl & DWC_TIM_CTRL_PWM) {
140 duty = (ld + 1) * dwc->clk_ns;
141 period = (ld2 + 1) * dwc->clk_ns;
142 period += duty;
143 } else {
144 duty = (ld + 1) * dwc->clk_ns;
145 period = duty * 2;
148 state->polarity = PWM_POLARITY_INVERSED;
149 state->period = period;
150 state->duty_cycle = duty;
152 pm_runtime_put_sync(pwmchip_parent(chip));
154 return 0;
157 static const struct pwm_ops dwc_pwm_ops = {
158 .apply = dwc_pwm_apply,
159 .get_state = dwc_pwm_get_state,
162 struct pwm_chip *dwc_pwm_alloc(struct device *dev)
164 struct pwm_chip *chip;
165 struct dwc_pwm *dwc;
167 chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(*dwc));
168 if (IS_ERR(chip))
169 return chip;
170 dwc = to_dwc_pwm(chip);
172 dwc->clk_ns = 10;
173 chip->ops = &dwc_pwm_ops;
175 return chip;
177 EXPORT_SYMBOL_GPL(dwc_pwm_alloc);
179 MODULE_AUTHOR("Felipe Balbi (Intel)");
180 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
181 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
182 MODULE_DESCRIPTION("DesignWare PWM Controller");
183 MODULE_LICENSE("GPL");