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