164 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright 2018 NXP4 * Dong Aisheng <aisheng.dong@nxp.com>5 */6 7#include <linux/bits.h>8#include <linux/clk-provider.h>9#include <linux/err.h>10#include <linux/io.h>11#include <linux/slab.h>12#include <linux/spinlock.h>13 14#include "clk-scu.h"15 16static DEFINE_SPINLOCK(imx_lpcg_scu_lock);17 18#define CLK_GATE_SCU_LPCG_MASK 0x319#define CLK_GATE_SCU_LPCG_HW_SEL BIT(0)20#define CLK_GATE_SCU_LPCG_SW_SEL BIT(1)21 22/*23 * struct clk_lpcg_scu - Description of LPCG clock24 *25 * @hw: clk_hw of this LPCG26 * @reg: register of this LPCG clock27 * @bit_idx: bit index of this LPCG clock28 * @hw_gate: HW auto gate enable29 *30 * This structure describes one LPCG clock31 */32struct clk_lpcg_scu {33 struct clk_hw hw;34 void __iomem *reg;35 u8 bit_idx;36 bool hw_gate;37 38 /* for state save&restore */39 u32 state;40};41 42#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)43 44static int clk_lpcg_scu_enable(struct clk_hw *hw)45{46 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);47 unsigned long flags;48 u32 reg, val;49 50 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);51 52 reg = readl_relaxed(clk->reg);53 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);54 55 val = CLK_GATE_SCU_LPCG_SW_SEL;56 if (clk->hw_gate)57 val |= CLK_GATE_SCU_LPCG_HW_SEL;58 59 reg |= val << clk->bit_idx;60 writel(reg, clk->reg);61 62 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);63 64 return 0;65}66 67static void clk_lpcg_scu_disable(struct clk_hw *hw)68{69 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);70 unsigned long flags;71 u32 reg;72 73 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);74 75 reg = readl_relaxed(clk->reg);76 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);77 writel(reg, clk->reg);78 79 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);80}81 82static const struct clk_ops clk_lpcg_scu_ops = {83 .enable = clk_lpcg_scu_enable,84 .disable = clk_lpcg_scu_disable,85};86 87struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,88 const char *parent_name, unsigned long flags,89 void __iomem *reg, u8 bit_idx, bool hw_gate)90{91 struct clk_lpcg_scu *clk;92 struct clk_init_data init;93 struct clk_hw *hw;94 int ret;95 96 clk = kzalloc(sizeof(*clk), GFP_KERNEL);97 if (!clk)98 return ERR_PTR(-ENOMEM);99 100 clk->reg = reg;101 clk->bit_idx = bit_idx;102 clk->hw_gate = hw_gate;103 104 init.name = name;105 init.ops = &clk_lpcg_scu_ops;106 init.flags = CLK_SET_RATE_PARENT | flags;107 init.parent_names = parent_name ? &parent_name : NULL;108 init.num_parents = parent_name ? 1 : 0;109 110 clk->hw.init = &init;111 112 hw = &clk->hw;113 ret = clk_hw_register(dev, hw);114 if (ret) {115 kfree(clk);116 hw = ERR_PTR(ret);117 return hw;118 }119 120 if (dev)121 dev_set_drvdata(dev, clk);122 123 return hw;124}125 126void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)127{128 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);129 130 clk_hw_unregister(&clk->hw);131 kfree(clk);132}133 134static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)135{136 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);137 138 clk->state = readl_relaxed(clk->reg);139 dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);140 141 return 0;142}143 144static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)145{146 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);147 148 /*149 * FIXME: Sometimes writes don't work unless the CPU issues150 * them twice151 */152 153 writel(clk->state, clk->reg);154 writel(clk->state, clk->reg);155 dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);156 157 return 0;158}159 160const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {161 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,162 imx_clk_lpcg_scu_resume)163};164