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