linux/drivers/clk/tegra/clk-pll-out.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/io.h>
   8#include <linux/err.h>
   9#include <linux/delay.h>
  10#include <linux/slab.h>
  11#include <linux/clk-provider.h>
  12
  13#include "clk.h"
  14
  15#define pll_out_enb(p) (BIT(p->enb_bit_idx))
  16#define pll_out_rst(p) (BIT(p->rst_bit_idx))
  17
  18static int clk_pll_out_is_enabled(struct clk_hw *hw)
  19{
  20        struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  21        u32 val = readl_relaxed(pll_out->reg);
  22        int state;
  23
  24        state = (val & pll_out_enb(pll_out)) ? 1 : 0;
  25        if (!(val & (pll_out_rst(pll_out))))
  26                state = 0;
  27        return state;
  28}
  29
  30static int clk_pll_out_enable(struct clk_hw *hw)
  31{
  32        struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  33        unsigned long flags = 0;
  34        u32 val;
  35
  36        if (pll_out->lock)
  37                spin_lock_irqsave(pll_out->lock, flags);
  38
  39        val = readl_relaxed(pll_out->reg);
  40
  41        val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
  42
  43        writel_relaxed(val, pll_out->reg);
  44        udelay(2);
  45
  46        if (pll_out->lock)
  47                spin_unlock_irqrestore(pll_out->lock, flags);
  48
  49        return 0;
  50}
  51
  52static void clk_pll_out_disable(struct clk_hw *hw)
  53{
  54        struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  55        unsigned long flags = 0;
  56        u32 val;
  57
  58        if (pll_out->lock)
  59                spin_lock_irqsave(pll_out->lock, flags);
  60
  61        val = readl_relaxed(pll_out->reg);
  62
  63        val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
  64
  65        writel_relaxed(val, pll_out->reg);
  66        udelay(2);
  67
  68        if (pll_out->lock)
  69                spin_unlock_irqrestore(pll_out->lock, flags);
  70}
  71
  72static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
  73{
  74        if (!__clk_get_enable_count(hw->clk))
  75                clk_pll_out_disable(hw);
  76        else
  77                clk_pll_out_enable(hw);
  78}
  79
  80const struct clk_ops tegra_clk_pll_out_ops = {
  81        .is_enabled = clk_pll_out_is_enabled,
  82        .enable = clk_pll_out_enable,
  83        .disable = clk_pll_out_disable,
  84        .restore_context = tegra_clk_pll_out_restore_context,
  85};
  86
  87struct clk *tegra_clk_register_pll_out(const char *name,
  88                const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
  89                u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
  90                spinlock_t *lock)
  91{
  92        struct tegra_clk_pll_out *pll_out;
  93        struct clk *clk;
  94        struct clk_init_data init;
  95
  96        pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
  97        if (!pll_out)
  98                return ERR_PTR(-ENOMEM);
  99
 100        init.name = name;
 101        init.ops = &tegra_clk_pll_out_ops;
 102        init.parent_names = (parent_name ? &parent_name : NULL);
 103        init.num_parents = (parent_name ? 1 : 0);
 104        init.flags = flags;
 105
 106        pll_out->reg = reg;
 107        pll_out->enb_bit_idx = enb_bit_idx;
 108        pll_out->rst_bit_idx = rst_bit_idx;
 109        pll_out->flags = pll_out_flags;
 110        pll_out->lock = lock;
 111
 112        /* Data in .init is copied by clk_register(), so stack variable OK */
 113        pll_out->hw.init = &init;
 114
 115        clk = clk_register(NULL, &pll_out->hw);
 116        if (IS_ERR(clk))
 117                kfree(pll_out);
 118
 119        return clk;
 120}
 121