^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2017~2018 NXP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define PCG_PCS_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define PCG_PCS_MASK 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define PCG_CGC_SHIFT 30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define PCG_FRAC_SHIFT 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define PCG_FRAC_WIDTH 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define PCG_FRAC_MASK BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define PCG_PCD_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define PCG_PCD_WIDTH 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define PCG_PCD_MASK 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) const char * const *parent_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int num_parents, bool mux_present,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) bool rate_present, bool gate_present,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) void __iomem *reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct clk_fractional_divider *fd = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct clk_gate *gate = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct clk_mux *mux = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (mux_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) mux = kzalloc(sizeof(*mux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (!mux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) mux_hw = &mux->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) mux->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) mux->shift = PCG_PCS_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) mux->mask = PCG_PCS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (rate_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) fd = kzalloc(sizeof(*fd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (!fd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) kfree(mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) fd_hw = &fd->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) fd->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) fd->mshift = PCG_FRAC_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) fd->mwidth = PCG_FRAC_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) fd->mmask = PCG_FRAC_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) fd->nshift = PCG_PCD_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) fd->nwidth = PCG_PCD_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) fd->nmask = PCG_PCD_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
^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) if (gate_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) gate = kzalloc(sizeof(*gate), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!gate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) kfree(mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) kfree(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) gate_hw = &gate->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) gate->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) gate->bit_idx = PCG_CGC_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) mux_hw, &clk_mux_ops, fd_hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) &clk_fractional_divider_ops, gate_hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) &clk_gate_ops, CLK_SET_RATE_GATE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) CLK_SET_PARENT_GATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (IS_ERR(hw)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) kfree(mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) kfree(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }