^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 (C) 2013 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/bits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * struct clk_fixup_mux - imx integer fixup multiplexer clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * @mux: the parent class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @ops: pointer to clk_ops of parent class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * @fixup: a hook to fixup the write value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * The imx fixup multiplexer clock is a subclass of basic clk_mux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * with an addtional fixup hook.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct clk_fixup_mux {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct clk_mux mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) const struct clk_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) void (*fixup)(u32 *val);
^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_fixup_mux *to_clk_fixup_mux(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_mux *mux = to_clk_mux(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return container_of(mux, struct clk_fixup_mux, mux);
^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 u8 clk_fixup_mux_get_parent(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return fixup_mux->ops->get_parent(&fixup_mux->mux.hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct clk_mux *mux = to_clk_mux(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) spin_lock_irqsave(mux->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) val = readl(mux->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) val &= ~(mux->mask << mux->shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) val |= index << mux->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) fixup_mux->fixup(&val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) writel(val, mux->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) spin_unlock_irqrestore(mux->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static const struct clk_ops clk_fixup_mux_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .get_parent = clk_fixup_mux_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .set_parent = clk_fixup_mux_set_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 shift, u8 width, const char * const *parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int num_parents, void (*fixup)(u32 *val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct clk_fixup_mux *fixup_mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (!fixup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) fixup_mux = kzalloc(sizeof(*fixup_mux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!fixup_mux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) init.ops = &clk_fixup_mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) init.parent_names = parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) init.num_parents = num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) init.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) fixup_mux->mux.reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) fixup_mux->mux.shift = shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) fixup_mux->mux.mask = BIT(width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) fixup_mux->mux.lock = &imx_ccm_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) fixup_mux->mux.hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) fixup_mux->ops = &clk_mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) fixup_mux->fixup = fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) hw = &fixup_mux->mux.hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ret = clk_hw_register(NULL, hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) kfree(fixup_mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }