Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Spreadtrum gate clock driver
0004 //
0005 // Copyright (C) 2017 Spreadtrum, Inc.
0006 // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
0007 
0008 #include <linux/clk-provider.h>
0009 #include <linux/regmap.h>
0010 
0011 #include "gate.h"
0012 
0013 static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
0014 {
0015     const struct sprd_clk_common *common = &sg->common;
0016     unsigned int reg;
0017     bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;
0018 
0019     set ^= en;
0020 
0021     regmap_read(common->regmap, common->reg, &reg);
0022 
0023     if (set)
0024         reg |= sg->enable_mask;
0025     else
0026         reg &= ~sg->enable_mask;
0027 
0028     regmap_write(common->regmap, common->reg, reg);
0029 }
0030 
0031 static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
0032 {
0033     const struct sprd_clk_common *common = &sg->common;
0034     bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
0035     unsigned int offset;
0036 
0037     set ^= en;
0038 
0039     /*
0040      * Each set/clear gate clock has three registers:
0041      * common->reg          - base register
0042      * common->reg + offset     - set register
0043      * common->reg + 2 * offset - clear register
0044      */
0045     offset = set ? sg->sc_offset : sg->sc_offset * 2;
0046 
0047     regmap_write(common->regmap, common->reg + offset,
0048               sg->enable_mask);
0049 }
0050 
0051 static void sprd_gate_disable(struct clk_hw *hw)
0052 {
0053     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0054 
0055     clk_gate_toggle(sg, false);
0056 }
0057 
0058 static int sprd_gate_enable(struct clk_hw *hw)
0059 {
0060     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0061 
0062     clk_gate_toggle(sg, true);
0063 
0064     return 0;
0065 }
0066 
0067 static void sprd_sc_gate_disable(struct clk_hw *hw)
0068 {
0069     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0070 
0071     clk_sc_gate_toggle(sg, false);
0072 }
0073 
0074 static int sprd_sc_gate_enable(struct clk_hw *hw)
0075 {
0076     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0077 
0078     clk_sc_gate_toggle(sg, true);
0079 
0080     return 0;
0081 }
0082 
0083 static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
0084 {
0085     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0086 
0087     clk_sc_gate_toggle(sg, true);
0088     udelay(sg->udelay);
0089 
0090     return 0;
0091 }
0092 
0093 static int sprd_gate_is_enabled(struct clk_hw *hw)
0094 {
0095     struct sprd_gate *sg = hw_to_sprd_gate(hw);
0096     struct sprd_clk_common *common = &sg->common;
0097     struct clk_hw *parent;
0098     unsigned int reg;
0099 
0100     if (sg->flags & SPRD_GATE_NON_AON) {
0101         parent = clk_hw_get_parent(hw);
0102         if (!parent || !clk_hw_is_enabled(parent))
0103             return 0;
0104     }
0105 
0106     regmap_read(common->regmap, common->reg, &reg);
0107 
0108     if (sg->flags & CLK_GATE_SET_TO_DISABLE)
0109         reg ^= sg->enable_mask;
0110 
0111     reg &= sg->enable_mask;
0112 
0113     return reg ? 1 : 0;
0114 }
0115 
0116 const struct clk_ops sprd_gate_ops = {
0117     .disable    = sprd_gate_disable,
0118     .enable     = sprd_gate_enable,
0119     .is_enabled = sprd_gate_is_enabled,
0120 };
0121 EXPORT_SYMBOL_GPL(sprd_gate_ops);
0122 
0123 const struct clk_ops sprd_sc_gate_ops = {
0124     .disable    = sprd_sc_gate_disable,
0125     .enable     = sprd_sc_gate_enable,
0126     .is_enabled = sprd_gate_is_enabled,
0127 };
0128 EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
0129 
0130 const struct clk_ops sprd_pll_sc_gate_ops = {
0131     .unprepare  = sprd_sc_gate_disable,
0132     .prepare    = sprd_pll_sc_gate_prepare,
0133     .is_enabled = sprd_gate_is_enabled,
0134 };
0135 EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);