Lines Matching +full:duty +full:- +full:cycle

1 // SPDX-License-Identifier: GPL-2.0+
6 * - When changing both duty cycle and period, we may end up with one cycle
7 * with the old duty cycle and the new period. This is because the counters
9 * automatically reloaded at the end of a cycle. If this automatic reload
11 * bad cycle. This could probably be fixed by reading TCR0 just before
13 * - Cannot produce 100% duty cycle by configuring the TLRs. This might be
14 * possible by stopping the counters at an appropriate point in the cycle,
16 * - Only produces "normal" output.
17 * - Always produces low output if disabled.
20 #include <clocksource/timer-xilinx.h>
22 #include <linux/clk-provider.h>
37 WARN_ON(cycles < 2 || cycles - 2 > priv->max); in xilinx_timer_tlr_cycles()
40 return cycles - 2; in xilinx_timer_tlr_cycles()
41 return priv->max - cycles + 2; in xilinx_timer_tlr_cycles()
52 cycles = (u64)priv->max - tlr + 2; in xilinx_timer_get_period()
56 clk_get_rate(priv->clk)); in xilinx_timer_get_period()
65 * - Set both timers to generate mode (MDT=1)
66 * - Set both timers to PWM mode (PWMA=1)
67 * - Enable the generate out signals (GENT=1)
71 * - The timer must be running (ENT=1)
72 * - The timer must auto-reload TLR into TCR (ARHT=1)
73 * - We must not be in the process of loading TLR into TCR (LOAD=0)
74 * - Cascade mode must be disabled (CASC=0)
91 return &container_of(chip, struct xilinx_pwm_device, chip)->priv; in xilinx_pwm_chip_to_priv()
108 if (state->polarity != PWM_POLARITY_NORMAL) in xilinx_pwm_apply()
109 return -EINVAL; in xilinx_pwm_apply()
113 * priv->max + 2. To enforce this we can reduce the cycles, but we may in xilinx_pwm_apply()
116 * duty cycle (% high time) than what was requested. in xilinx_pwm_apply()
118 rate = clk_get_rate(priv->clk); in xilinx_pwm_apply()
120 period_cycles = min_t(u64, state->period, U32_MAX * NSEC_PER_SEC); in xilinx_pwm_apply()
122 period_cycles = min_t(u64, period_cycles, priv->max + 2); in xilinx_pwm_apply()
124 return -ERANGE; in xilinx_pwm_apply()
126 /* Same thing for duty cycles */ in xilinx_pwm_apply()
127 duty_cycles = min_t(u64, state->duty_cycle, U32_MAX * NSEC_PER_SEC); in xilinx_pwm_apply()
129 duty_cycles = min_t(u64, duty_cycles, priv->max + 2); in xilinx_pwm_apply()
132 * If we specify 100% duty cycle, we will get 0% instead, so decrease in xilinx_pwm_apply()
133 * the duty cycle count by one. in xilinx_pwm_apply()
136 duty_cycles = period_cycles - 1; in xilinx_pwm_apply()
138 /* Round down to 0% duty cycle for unrepresentable duty cycles */ in xilinx_pwm_apply()
142 regmap_read(priv->map, TCSR0, &tcsr0); in xilinx_pwm_apply()
143 regmap_read(priv->map, TCSR1, &tcsr1); in xilinx_pwm_apply()
146 regmap_write(priv->map, TLR0, tlr0); in xilinx_pwm_apply()
147 regmap_write(priv->map, TLR1, tlr1); in xilinx_pwm_apply()
149 if (state->enabled) { in xilinx_pwm_apply()
152 * reloaded at the end of the current cycle. in xilinx_pwm_apply()
156 regmap_write(priv->map, TCSR0, tcsr0 | TCSR_LOAD); in xilinx_pwm_apply()
157 regmap_write(priv->map, TCSR1, tcsr1 | TCSR_LOAD); in xilinx_pwm_apply()
161 regmap_write(priv->map, TCSR0, tcsr0); in xilinx_pwm_apply()
162 regmap_write(priv->map, TCSR1, tcsr1); in xilinx_pwm_apply()
165 regmap_write(priv->map, TCSR0, 0); in xilinx_pwm_apply()
166 regmap_write(priv->map, TCSR1, 0); in xilinx_pwm_apply()
179 regmap_read(priv->map, TLR0, &tlr0); in xilinx_pwm_get_state()
180 regmap_read(priv->map, TLR1, &tlr1); in xilinx_pwm_get_state()
181 regmap_read(priv->map, TCSR0, &tcsr0); in xilinx_pwm_get_state()
182 regmap_read(priv->map, TCSR1, &tcsr1); in xilinx_pwm_get_state()
183 state->period = xilinx_timer_get_period(priv, tlr0, tcsr0); in xilinx_pwm_get_state()
184 state->duty_cycle = xilinx_timer_get_period(priv, tlr1, tcsr1); in xilinx_pwm_get_state()
185 state->enabled = xilinx_timer_pwm_enabled(tcsr0, tcsr1); in xilinx_pwm_get_state()
186 state->polarity = PWM_POLARITY_NORMAL; in xilinx_pwm_get_state()
189 * 100% duty cycle results in constant low output. This may be (very) in xilinx_pwm_get_state()
192 if (state->period == state->duty_cycle) in xilinx_pwm_get_state()
193 state->duty_cycle = 0; in xilinx_pwm_get_state()
215 struct device *dev = &pdev->dev; in xilinx_pwm_probe()
216 struct device_node *np = dev->of_node; in xilinx_pwm_probe()
223 ret = of_property_read_u32(np, "#pwm-cells", &pwm_cells); in xilinx_pwm_probe()
224 if (ret == -EINVAL) in xilinx_pwm_probe()
225 return -ENODEV; in xilinx_pwm_probe()
227 return dev_err_probe(dev, ret, "could not read #pwm-cells\n"); in xilinx_pwm_probe()
231 return -ENOMEM; in xilinx_pwm_probe()
233 priv = &xilinx_pwm->priv; in xilinx_pwm_probe()
239 priv->map = devm_regmap_init_mmio(dev, regs, in xilinx_pwm_probe()
241 if (IS_ERR(priv->map)) in xilinx_pwm_probe()
242 return dev_err_probe(dev, PTR_ERR(priv->map), in xilinx_pwm_probe()
245 ret = of_property_read_u32(np, "xlnx,one-timer-only", &one_timer); in xilinx_pwm_probe()
248 "Could not read xlnx,one-timer-only\n"); in xilinx_pwm_probe()
251 return dev_err_probe(dev, -EINVAL, in xilinx_pwm_probe()
254 ret = of_property_read_u32(np, "xlnx,count-width", &width); in xilinx_pwm_probe()
255 if (ret == -EINVAL) in xilinx_pwm_probe()
259 "Could not read xlnx,count-width\n"); in xilinx_pwm_probe()
262 return dev_err_probe(dev, -EINVAL, in xilinx_pwm_probe()
264 priv->max = BIT_ULL(width) - 1; in xilinx_pwm_probe()
272 priv->clk = devm_clk_get(dev, "s_axi_aclk"); in xilinx_pwm_probe()
273 if (IS_ERR(priv->clk)) in xilinx_pwm_probe()
274 return dev_err_probe(dev, PTR_ERR(priv->clk), in xilinx_pwm_probe()
277 ret = clk_prepare_enable(priv->clk); in xilinx_pwm_probe()
280 clk_rate_exclusive_get(priv->clk); in xilinx_pwm_probe()
282 xilinx_pwm->chip.dev = dev; in xilinx_pwm_probe()
283 xilinx_pwm->chip.ops = &xilinx_pwm_ops; in xilinx_pwm_probe()
284 xilinx_pwm->chip.npwm = 1; in xilinx_pwm_probe()
285 ret = pwmchip_add(&xilinx_pwm->chip); in xilinx_pwm_probe()
287 clk_rate_exclusive_put(priv->clk); in xilinx_pwm_probe()
288 clk_disable_unprepare(priv->clk); in xilinx_pwm_probe()
299 pwmchip_remove(&xilinx_pwm->chip); in xilinx_pwm_remove()
300 clk_rate_exclusive_put(xilinx_pwm->priv.clk); in xilinx_pwm_remove()
301 clk_disable_unprepare(xilinx_pwm->priv.clk); in xilinx_pwm_remove()
305 { .compatible = "xlnx,xps-timer-1.00.a", },
314 .name = "xilinx-pwm",
320 MODULE_ALIAS("platform:xilinx-pwm");