Lines Matching +full:io +full:- +full:channel +full:- +full:mux
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>
35 #include <linux/io.h>
93 struct clk_mux mux; member
124 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_request() local
125 struct device *dev = chip->dev; in meson_pwm_request()
128 err = clk_prepare_enable(channel->clk); in meson_pwm_request()
131 __clk_get_name(channel->clk), err); in meson_pwm_request()
141 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_free() local
143 clk_disable_unprepare(channel->clk); in meson_pwm_free()
149 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_calc() local
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()
172 dev_err(meson->chip.dev, "invalid source clock frequency\n"); in meson_pwm_calc()
173 return -EINVAL; in meson_pwm_calc()
176 dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); in meson_pwm_calc()
180 dev_err(meson->chip.dev, "unable to get period cnt\n"); in meson_pwm_calc()
181 return -EINVAL; in meson_pwm_calc()
184 dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt); in meson_pwm_calc()
187 channel->hi = cnt; in meson_pwm_calc()
188 channel->lo = 0; in meson_pwm_calc()
190 channel->hi = 0; in meson_pwm_calc()
191 channel->lo = cnt; in meson_pwm_calc()
195 dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt); in meson_pwm_calc()
197 channel->hi = duty_cnt; in meson_pwm_calc()
198 channel->lo = cnt - duty_cnt; in meson_pwm_calc()
201 channel->rate = fin_freq; in meson_pwm_calc()
208 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_enable() local
214 channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; in meson_pwm_enable()
216 err = clk_set_rate(channel->clk, channel->rate); in meson_pwm_enable()
218 dev_err(meson->chip.dev, "setting clock rate failed\n"); in meson_pwm_enable()
220 spin_lock_irqsave(&meson->lock, flags); in meson_pwm_enable()
222 value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) | in meson_pwm_enable()
223 FIELD_PREP(PWM_LOW_MASK, channel->lo); in meson_pwm_enable()
224 writel(value, meson->base + channel_data->reg_offset); in meson_pwm_enable()
226 value = readl(meson->base + REG_MISC_AB); in meson_pwm_enable()
227 value |= channel_data->pwm_en_mask; in meson_pwm_enable()
228 writel(value, meson->base + REG_MISC_AB); in meson_pwm_enable()
230 spin_unlock_irqrestore(&meson->lock, flags); in meson_pwm_enable()
238 spin_lock_irqsave(&meson->lock, flags); in meson_pwm_disable()
240 value = readl(meson->base + REG_MISC_AB); in meson_pwm_disable()
241 value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; in meson_pwm_disable()
242 writel(value, meson->base + REG_MISC_AB); in meson_pwm_disable()
244 spin_unlock_irqrestore(&meson->lock, flags); in meson_pwm_disable()
251 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; in meson_pwm_apply() local
254 if (!state->enabled) { in meson_pwm_apply()
255 if (state->polarity == PWM_POLARITY_INVERSED) { in meson_pwm_apply()
259 * Instead we achieve this by setting mux parent with in meson_pwm_apply()
268 channel->rate = ULONG_MAX; in meson_pwm_apply()
269 channel->hi = ~0; in meson_pwm_apply()
270 channel->lo = 0; in meson_pwm_apply()
291 struct meson_pwm_channel *channel; in meson_pwm_cnt_to_ns() local
295 channel = &meson->channels[pwm->hwpwm]; in meson_pwm_cnt_to_ns()
297 fin_freq = clk_get_rate(channel->clk); in meson_pwm_cnt_to_ns()
309 struct meson_pwm_channel *channel; in meson_pwm_get_state() local
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()
400 .compatible = "amlogic,meson8b-pwm",
404 .compatible = "amlogic,meson-gxbb-pwm",
408 .compatible = "amlogic,meson-gxbb-ao-pwm",
412 .compatible = "amlogic,meson-axg-ee-pwm",
416 .compatible = "amlogic,meson-axg-ao-pwm",
420 .compatible = "amlogic,meson-g12a-ee-pwm",
424 .compatible = "amlogic,meson-g12a-ao-pwm-ab",
428 .compatible = "amlogic,meson-g12a-ao-pwm-cd",
438 struct device *dev = meson->chip.dev; in meson_pwm_init_channels()
443 for (i = 0; i < meson->data->num_parents; i++) { in meson_pwm_init_channels()
444 mux_parent_data[i].index = -1; in meson_pwm_init_channels()
445 mux_parent_data[i].name = meson->data->parent_names[i]; in meson_pwm_init_channels()
448 for (i = 0; i < meson->chip.npwm; i++) { in meson_pwm_init_channels()
449 struct meson_pwm_channel *channel = &meson->channels[i]; in meson_pwm_init_channels() local
453 snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i); in meson_pwm_init_channels()
459 init.num_parents = meson->data->num_parents; in meson_pwm_init_channels()
461 channel->mux.reg = meson->base + REG_MISC_AB; in meson_pwm_init_channels()
462 channel->mux.shift = in meson_pwm_init_channels()
464 channel->mux.mask = MISC_CLK_SEL_MASK; in meson_pwm_init_channels()
465 channel->mux.flags = 0; in meson_pwm_init_channels()
466 channel->mux.lock = &meson->lock; in meson_pwm_init_channels()
467 channel->mux.table = NULL; in meson_pwm_init_channels()
468 channel->mux.hw.init = &init; in meson_pwm_init_channels()
470 err = devm_clk_hw_register(dev, &channel->mux.hw); in meson_pwm_init_channels()
480 div_parent.index = -1; in meson_pwm_init_channels()
481 div_parent.hw = &channel->mux.hw; in meson_pwm_init_channels()
485 channel->div.reg = meson->base + REG_MISC_AB; in meson_pwm_init_channels()
486 channel->div.shift = meson_pwm_per_channel_data[i].clk_div_shift; in meson_pwm_init_channels()
487 channel->div.width = MISC_CLK_DIV_WIDTH; in meson_pwm_init_channels()
488 channel->div.hw.init = &init; in meson_pwm_init_channels()
489 channel->div.flags = 0; in meson_pwm_init_channels()
490 channel->div.lock = &meson->lock; in meson_pwm_init_channels()
492 err = devm_clk_hw_register(dev, &channel->div.hw); in meson_pwm_init_channels()
502 gate_parent.index = -1; in meson_pwm_init_channels()
503 gate_parent.hw = &channel->div.hw; in meson_pwm_init_channels()
507 channel->gate.reg = meson->base + REG_MISC_AB; in meson_pwm_init_channels()
508 channel->gate.bit_idx = meson_pwm_per_channel_data[i].clk_en_shift; in meson_pwm_init_channels()
509 channel->gate.hw.init = &init; in meson_pwm_init_channels()
510 channel->gate.flags = 0; in meson_pwm_init_channels()
511 channel->gate.lock = &meson->lock; in meson_pwm_init_channels()
513 err = devm_clk_hw_register(dev, &channel->gate.hw); in meson_pwm_init_channels()
517 channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL); in meson_pwm_init_channels()
518 if (IS_ERR(channel->clk)) in meson_pwm_init_channels()
519 return dev_err_probe(dev, PTR_ERR(channel->clk), in meson_pwm_init_channels()
531 meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL); in meson_pwm_probe()
533 return -ENOMEM; in meson_pwm_probe()
535 meson->base = devm_platform_ioremap_resource(pdev, 0); in meson_pwm_probe()
536 if (IS_ERR(meson->base)) in meson_pwm_probe()
537 return PTR_ERR(meson->base); in meson_pwm_probe()
539 spin_lock_init(&meson->lock); in meson_pwm_probe()
540 meson->chip.dev = &pdev->dev; in meson_pwm_probe()
541 meson->chip.ops = &meson_pwm_ops; in meson_pwm_probe()
542 meson->chip.npwm = MESON_NUM_PWMS; in meson_pwm_probe()
544 meson->data = of_device_get_match_data(&pdev->dev); in meson_pwm_probe()
550 err = devm_pwmchip_add(&pdev->dev, &meson->chip); in meson_pwm_probe()
552 return dev_err_probe(&pdev->dev, err, in meson_pwm_probe()
560 .name = "meson-pwm",