Lines Matching +full:hw +full:- +full:channels
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
13 * Setting the duty cycle will disable and re-enable the PWM output.
19 * https://dl.khadas.com/Hardware/VIM2/Datasheet/S912_Datasheet_V0.220170314publicversion-Wesion.pdf
23 * https://dn.odroid.com/S922X/ODROID-N2/Datasheet/S922X_Public_Datasheet_V0.2.pdf
33 #include <linux/clk-provider.h>
106 struct meson_pwm_channel channels[MESON_NUM_PWMS]; member
123 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_request()
127 err = clk_prepare_enable(channel->clk); in meson_pwm_request()
130 __clk_get_name(channel->clk), err); in meson_pwm_request()
140 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_free()
142 clk_disable_unprepare(channel->clk); in meson_pwm_free()
149 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_calc()
154 duty = state->duty_cycle; in meson_pwm_calc()
155 period = state->period; in meson_pwm_calc()
163 if (state->polarity == PWM_POLARITY_INVERSED) in meson_pwm_calc()
164 duty = period - duty; in meson_pwm_calc()
170 fin_freq = clk_round_rate(channel->clk, freq); in meson_pwm_calc()
174 return fin_freq ? fin_freq : -EINVAL; in meson_pwm_calc()
182 return -EINVAL; in meson_pwm_calc()
188 channel->hi = cnt; in meson_pwm_calc()
189 channel->lo = 0; in meson_pwm_calc()
191 channel->hi = 0; in meson_pwm_calc()
192 channel->lo = cnt; in meson_pwm_calc()
198 channel->hi = duty_cnt; in meson_pwm_calc()
199 channel->lo = cnt - duty_cnt; in meson_pwm_calc()
202 channel->rate = fin_freq; in meson_pwm_calc()
210 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_enable()
216 channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; in meson_pwm_enable()
218 err = clk_set_rate(channel->clk, channel->rate); in meson_pwm_enable()
222 spin_lock_irqsave(&meson->lock, flags); in meson_pwm_enable()
224 value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) | in meson_pwm_enable()
225 FIELD_PREP(PWM_LOW_MASK, channel->lo); in meson_pwm_enable()
226 writel(value, meson->base + channel_data->reg_offset); in meson_pwm_enable()
228 value = readl(meson->base + REG_MISC_AB); in meson_pwm_enable()
229 value |= channel_data->pwm_en_mask; in meson_pwm_enable()
230 writel(value, meson->base + REG_MISC_AB); in meson_pwm_enable()
232 spin_unlock_irqrestore(&meson->lock, flags); in meson_pwm_enable()
241 spin_lock_irqsave(&meson->lock, flags); in meson_pwm_disable()
243 value = readl(meson->base + REG_MISC_AB); in meson_pwm_disable()
244 value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; in meson_pwm_disable()
245 writel(value, meson->base + REG_MISC_AB); in meson_pwm_disable()
247 spin_unlock_irqrestore(&meson->lock, flags); in meson_pwm_disable()
254 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_apply()
257 if (!state->enabled) { in meson_pwm_apply()
258 if (state->polarity == PWM_POLARITY_INVERSED) { in meson_pwm_apply()
271 channel->rate = ULONG_MAX; in meson_pwm_apply()
272 channel->hi = ~0; in meson_pwm_apply()
273 channel->lo = 0; in meson_pwm_apply()
298 channel = &meson->channels[pwm->hwpwm]; in meson_pwm_cnt_to_ns()
300 fin_freq = clk_get_rate(channel->clk); in meson_pwm_cnt_to_ns()
315 channel = &meson->channels[pwm->hwpwm]; in meson_pwm_get_state()
316 channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; in meson_pwm_get_state()
318 value = readl(meson->base + REG_MISC_AB); in meson_pwm_get_state()
319 state->enabled = value & channel_data->pwm_en_mask; in meson_pwm_get_state()
321 value = readl(meson->base + channel_data->reg_offset); in meson_pwm_get_state()
322 channel->lo = FIELD_GET(PWM_LOW_MASK, value); in meson_pwm_get_state()
323 channel->hi = FIELD_GET(PWM_HIGH_MASK, value); in meson_pwm_get_state()
325 state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->lo + channel->hi); in meson_pwm_get_state()
326 state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); in meson_pwm_get_state()
328 state->polarity = PWM_POLARITY_NORMAL; in meson_pwm_get_state()
350 struct meson_pwm_channel *channel = &meson->channels[i]; in meson_pwm_init_clocks_meson8b()
362 channel->mux.reg = meson->base + REG_MISC_AB; in meson_pwm_init_clocks_meson8b()
363 channel->mux.shift = in meson_pwm_init_clocks_meson8b()
365 channel->mux.mask = MISC_CLK_SEL_MASK; in meson_pwm_init_clocks_meson8b()
366 channel->mux.flags = 0; in meson_pwm_init_clocks_meson8b()
367 channel->mux.lock = &meson->lock; in meson_pwm_init_clocks_meson8b()
368 channel->mux.table = NULL; in meson_pwm_init_clocks_meson8b()
369 channel->mux.hw.init = &init; in meson_pwm_init_clocks_meson8b()
371 err = devm_clk_hw_register(dev, &channel->mux.hw); in meson_pwm_init_clocks_meson8b()
381 div_parent.index = -1; in meson_pwm_init_clocks_meson8b()
382 div_parent.hw = &channel->mux.hw; in meson_pwm_init_clocks_meson8b()
386 channel->div.reg = meson->base + REG_MISC_AB; in meson_pwm_init_clocks_meson8b()
387 channel->div.shift = meson_pwm_per_channel_data[i].clk_div_shift; in meson_pwm_init_clocks_meson8b()
388 channel->div.width = MISC_CLK_DIV_WIDTH; in meson_pwm_init_clocks_meson8b()
389 channel->div.hw.init = &init; in meson_pwm_init_clocks_meson8b()
390 channel->div.flags = 0; in meson_pwm_init_clocks_meson8b()
391 channel->div.lock = &meson->lock; in meson_pwm_init_clocks_meson8b()
393 err = devm_clk_hw_register(dev, &channel->div.hw); in meson_pwm_init_clocks_meson8b()
403 gate_parent.index = -1; in meson_pwm_init_clocks_meson8b()
404 gate_parent.hw = &channel->div.hw; in meson_pwm_init_clocks_meson8b()
408 channel->gate.reg = meson->base + REG_MISC_AB; in meson_pwm_init_clocks_meson8b()
409 channel->gate.bit_idx = meson_pwm_per_channel_data[i].clk_en_shift; in meson_pwm_init_clocks_meson8b()
410 channel->gate.hw.init = &init; in meson_pwm_init_clocks_meson8b()
411 channel->gate.flags = 0; in meson_pwm_init_clocks_meson8b()
412 channel->gate.lock = &meson->lock; in meson_pwm_init_clocks_meson8b()
414 err = devm_clk_hw_register(dev, &channel->gate.hw); in meson_pwm_init_clocks_meson8b()
418 channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL); in meson_pwm_init_clocks_meson8b()
419 if (IS_ERR(channel->clk)) in meson_pwm_init_clocks_meson8b()
420 return dev_err_probe(dev, PTR_ERR(channel->clk), in meson_pwm_init_clocks_meson8b()
437 mux_parent_data[i].index = -1; in meson_pwm_init_channels_meson8b_legacy()
438 mux_parent_data[i].name = meson->data->parent_names[i]; in meson_pwm_init_channels_meson8b_legacy()
454 * Also DT requires clock-names to be explicitly ordered, so there is in meson_pwm_init_channels_meson8b_v2()
473 struct device_node *np = dev->of_node; in meson_pwm_init_channels_s4()
478 meson->channels[i].clk = of_clk_get(np, i); in meson_pwm_init_channels_s4()
479 if (IS_ERR(meson->channels[i].clk)) in meson_pwm_init_channels_s4()
481 PTR_ERR(meson->channels[i].clk), in meson_pwm_init_channels_s4()
485 meson->channels[i].clk); in meson_pwm_init_channels_s4()
538 .compatible = "amlogic,meson8-pwm-v2",
543 .compatible = "amlogic,meson8b-pwm",
547 .compatible = "amlogic,meson-gxbb-pwm",
551 .compatible = "amlogic,meson-gxbb-ao-pwm",
555 .compatible = "amlogic,meson-axg-ee-pwm",
559 .compatible = "amlogic,meson-axg-ao-pwm",
563 .compatible = "amlogic,meson-g12a-ee-pwm",
567 .compatible = "amlogic,meson-g12a-ao-pwm-ab",
571 .compatible = "amlogic,meson-g12a-ao-pwm-cd",
575 .compatible = "amlogic,meson-s4-pwm",
588 chip = devm_pwmchip_alloc(&pdev->dev, MESON_NUM_PWMS, sizeof(*meson)); in meson_pwm_probe()
593 meson->base = devm_platform_ioremap_resource(pdev, 0); in meson_pwm_probe()
594 if (IS_ERR(meson->base)) in meson_pwm_probe()
595 return PTR_ERR(meson->base); in meson_pwm_probe()
597 spin_lock_init(&meson->lock); in meson_pwm_probe()
598 chip->ops = &meson_pwm_ops; in meson_pwm_probe()
600 meson->data = of_device_get_match_data(&pdev->dev); in meson_pwm_probe()
602 err = meson->data->channels_init(chip); in meson_pwm_probe()
606 err = devm_pwmchip_add(&pdev->dev, chip); in meson_pwm_probe()
608 return dev_err_probe(&pdev->dev, err, in meson_pwm_probe()
616 .name = "meson-pwm",