brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · dd5abd0 Raw
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