linux/drivers/clk/sprd/gate.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Spreadtrum gate clock driver
   4//
   5// Copyright (C) 2017 Spreadtrum, Inc.
   6// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
   7
   8#include <linux/clk-provider.h>
   9#include <linux/regmap.h>
  10
  11#include "gate.h"
  12
  13static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
  14{
  15        const struct sprd_clk_common *common = &sg->common;
  16        unsigned int reg;
  17        bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;
  18
  19        set ^= en;
  20
  21        regmap_read(common->regmap, common->reg, &reg);
  22
  23        if (set)
  24                reg |= sg->enable_mask;
  25        else
  26                reg &= ~sg->enable_mask;
  27
  28        regmap_write(common->regmap, common->reg, reg);
  29}
  30
  31static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
  32{
  33        const struct sprd_clk_common *common = &sg->common;
  34        bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
  35        unsigned int offset;
  36
  37        set ^= en;
  38
  39        /*
  40         * Each set/clear gate clock has three registers:
  41         * common->reg                  - base register
  42         * common->reg + offset         - set register
  43         * common->reg + 2 * offset     - clear register
  44         */
  45        offset = set ? sg->sc_offset : sg->sc_offset * 2;
  46
  47        regmap_write(common->regmap, common->reg + offset,
  48                          sg->enable_mask);
  49}
  50
  51static void sprd_gate_disable(struct clk_hw *hw)
  52{
  53        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  54
  55        clk_gate_toggle(sg, false);
  56}
  57
  58static int sprd_gate_enable(struct clk_hw *hw)
  59{
  60        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  61
  62        clk_gate_toggle(sg, true);
  63
  64        return 0;
  65}
  66
  67static void sprd_sc_gate_disable(struct clk_hw *hw)
  68{
  69        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  70
  71        clk_sc_gate_toggle(sg, false);
  72}
  73
  74static int sprd_sc_gate_enable(struct clk_hw *hw)
  75{
  76        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  77
  78        clk_sc_gate_toggle(sg, true);
  79
  80        return 0;
  81}
  82
  83static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
  84{
  85        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  86
  87        clk_sc_gate_toggle(sg, true);
  88        udelay(sg->udelay);
  89
  90        return 0;
  91}
  92
  93static int sprd_gate_is_enabled(struct clk_hw *hw)
  94{
  95        struct sprd_gate *sg = hw_to_sprd_gate(hw);
  96        struct sprd_clk_common *common = &sg->common;
  97        struct clk_hw *parent;
  98        unsigned int reg;
  99
 100        if (sg->flags & SPRD_GATE_NON_AON) {
 101                parent = clk_hw_get_parent(hw);
 102                if (!parent || !clk_hw_is_enabled(parent))
 103                        return 0;
 104        }
 105
 106        regmap_read(common->regmap, common->reg, &reg);
 107
 108        if (sg->flags & CLK_GATE_SET_TO_DISABLE)
 109                reg ^= sg->enable_mask;
 110
 111        reg &= sg->enable_mask;
 112
 113        return reg ? 1 : 0;
 114}
 115
 116const struct clk_ops sprd_gate_ops = {
 117        .disable        = sprd_gate_disable,
 118        .enable         = sprd_gate_enable,
 119        .is_enabled     = sprd_gate_is_enabled,
 120};
 121EXPORT_SYMBOL_GPL(sprd_gate_ops);
 122
 123const struct clk_ops sprd_sc_gate_ops = {
 124        .disable        = sprd_sc_gate_disable,
 125        .enable         = sprd_sc_gate_enable,
 126        .is_enabled     = sprd_gate_is_enabled,
 127};
 128EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
 129
 130const struct clk_ops sprd_pll_sc_gate_ops = {
 131        .unprepare      = sprd_sc_gate_disable,
 132        .prepare        = sprd_pll_sc_gate_prepare,
 133        .is_enabled     = sprd_gate_is_enabled,
 134};
 135EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);
 136