^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2012 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * struct clk_div - mxs integer divider clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * @divider: the parent class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * @ops: pointer to clk_ops of parent class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * @reg: register address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @busy: busy bit shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * The mxs divider clock is a subclass of basic clk_divider with an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * addtional busy bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct clk_div {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct clk_divider divider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) const struct clk_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) u8 busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static inline struct clk_div *to_clk_div(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct clk_divider *divider = to_clk_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return container_of(divider, struct clk_div, divider);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static unsigned long clk_div_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct clk_div *div = to_clk_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return div->ops->recalc_rate(&div->divider.hw, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct clk_div *div = to_clk_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return div->ops->round_rate(&div->divider.hw, rate, prate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct clk_div *div = to_clk_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ret = mxs_clk_wait(div->reg, div->busy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static const struct clk_ops clk_div_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .recalc_rate = clk_div_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .round_rate = clk_div_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .set_rate = clk_div_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct clk *mxs_clk_div(const char *name, const char *parent_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) void __iomem *reg, u8 shift, u8 width, u8 busy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct clk_div *div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) div = kzalloc(sizeof(*div), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (!div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) init.ops = &clk_div_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) init.flags = CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) init.parent_names = (parent_name ? &parent_name: NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) init.num_parents = (parent_name ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) div->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) div->busy = busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) div->divider.reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) div->divider.shift = shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) div->divider.width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) div->divider.flags = CLK_DIVIDER_ONE_BASED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) div->divider.lock = &mxs_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) div->divider.hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) div->ops = &clk_divider_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) clk = clk_register(NULL, &div->divider.hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) kfree(div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }