linux/drivers/clk/mediatek/clk-gate.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014 MediaTek Inc.
   4 * Author: James Liao <jamesjj.liao@mediatek.com>
   5 */
   6
   7#include <linux/of.h>
   8#include <linux/of_address.h>
   9
  10#include <linux/io.h>
  11#include <linux/slab.h>
  12#include <linux/delay.h>
  13#include <linux/clkdev.h>
  14
  15#include "clk-mtk.h"
  16#include "clk-gate.h"
  17
  18static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
  19{
  20        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  21        u32 val;
  22
  23        regmap_read(cg->regmap, cg->sta_ofs, &val);
  24
  25        val &= BIT(cg->bit);
  26
  27        return val == 0;
  28}
  29
  30static int mtk_cg_bit_is_set(struct clk_hw *hw)
  31{
  32        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  33        u32 val;
  34
  35        regmap_read(cg->regmap, cg->sta_ofs, &val);
  36
  37        val &= BIT(cg->bit);
  38
  39        return val != 0;
  40}
  41
  42static void mtk_cg_set_bit(struct clk_hw *hw)
  43{
  44        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  45
  46        regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
  47}
  48
  49static void mtk_cg_clr_bit(struct clk_hw *hw)
  50{
  51        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  52
  53        regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
  54}
  55
  56static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
  57{
  58        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  59        u32 cgbit = BIT(cg->bit);
  60
  61        regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, cgbit);
  62}
  63
  64static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
  65{
  66        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
  67        u32 cgbit = BIT(cg->bit);
  68
  69        regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, 0);
  70}
  71
  72static int mtk_cg_enable(struct clk_hw *hw)
  73{
  74        mtk_cg_clr_bit(hw);
  75
  76        return 0;
  77}
  78
  79static void mtk_cg_disable(struct clk_hw *hw)
  80{
  81        mtk_cg_set_bit(hw);
  82}
  83
  84static int mtk_cg_enable_inv(struct clk_hw *hw)
  85{
  86        mtk_cg_set_bit(hw);
  87
  88        return 0;
  89}
  90
  91static void mtk_cg_disable_inv(struct clk_hw *hw)
  92{
  93        mtk_cg_clr_bit(hw);
  94}
  95
  96static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
  97{
  98        mtk_cg_clr_bit_no_setclr(hw);
  99
 100        return 0;
 101}
 102
 103static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
 104{
 105        mtk_cg_set_bit_no_setclr(hw);
 106}
 107
 108static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw)
 109{
 110        mtk_cg_set_bit_no_setclr(hw);
 111
 112        return 0;
 113}
 114
 115static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
 116{
 117        mtk_cg_clr_bit_no_setclr(hw);
 118}
 119
 120const struct clk_ops mtk_clk_gate_ops_setclr = {
 121        .is_enabled     = mtk_cg_bit_is_cleared,
 122        .enable         = mtk_cg_enable,
 123        .disable        = mtk_cg_disable,
 124};
 125
 126const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
 127        .is_enabled     = mtk_cg_bit_is_set,
 128        .enable         = mtk_cg_enable_inv,
 129        .disable        = mtk_cg_disable_inv,
 130};
 131
 132const struct clk_ops mtk_clk_gate_ops_no_setclr = {
 133        .is_enabled     = mtk_cg_bit_is_cleared,
 134        .enable         = mtk_cg_enable_no_setclr,
 135        .disable        = mtk_cg_disable_no_setclr,
 136};
 137
 138const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
 139        .is_enabled     = mtk_cg_bit_is_set,
 140        .enable         = mtk_cg_enable_inv_no_setclr,
 141        .disable        = mtk_cg_disable_inv_no_setclr,
 142};
 143
 144struct clk *mtk_clk_register_gate(
 145                const char *name,
 146                const char *parent_name,
 147                struct regmap *regmap,
 148                int set_ofs,
 149                int clr_ofs,
 150                int sta_ofs,
 151                u8 bit,
 152                const struct clk_ops *ops,
 153                unsigned long flags,
 154                struct device *dev)
 155{
 156        struct mtk_clk_gate *cg;
 157        struct clk *clk;
 158        struct clk_init_data init = {};
 159
 160        cg = kzalloc(sizeof(*cg), GFP_KERNEL);
 161        if (!cg)
 162                return ERR_PTR(-ENOMEM);
 163
 164        init.name = name;
 165        init.flags = flags | CLK_SET_RATE_PARENT;
 166        init.parent_names = parent_name ? &parent_name : NULL;
 167        init.num_parents = parent_name ? 1 : 0;
 168        init.ops = ops;
 169
 170        cg->regmap = regmap;
 171        cg->set_ofs = set_ofs;
 172        cg->clr_ofs = clr_ofs;
 173        cg->sta_ofs = sta_ofs;
 174        cg->bit = bit;
 175
 176        cg->hw.init = &init;
 177
 178        clk = clk_register(dev, &cg->hw);
 179        if (IS_ERR(clk))
 180                kfree(cg);
 181
 182        return clk;
 183}
 184