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