162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * mmp AXI peripharal clock operation source file
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Marvell
662306a36Sopenharmony_ci * Chao Xie <xiechao.mail@gmail.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "clk.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk))
1862306a36Sopenharmony_cistruct clk_apmu {
1962306a36Sopenharmony_ci	struct clk_hw   hw;
2062306a36Sopenharmony_ci	void __iomem    *base;
2162306a36Sopenharmony_ci	u32		rst_mask;
2262306a36Sopenharmony_ci	u32		enable_mask;
2362306a36Sopenharmony_ci	spinlock_t	*lock;
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int clk_apmu_enable(struct clk_hw *hw)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct clk_apmu *apmu = to_clk_apmu(hw);
2962306a36Sopenharmony_ci	unsigned long data;
3062306a36Sopenharmony_ci	unsigned long flags = 0;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (apmu->lock)
3362306a36Sopenharmony_ci		spin_lock_irqsave(apmu->lock, flags);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	data = readl_relaxed(apmu->base) | apmu->enable_mask;
3662306a36Sopenharmony_ci	writel_relaxed(data, apmu->base);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (apmu->lock)
3962306a36Sopenharmony_ci		spin_unlock_irqrestore(apmu->lock, flags);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic void clk_apmu_disable(struct clk_hw *hw)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct clk_apmu *apmu = to_clk_apmu(hw);
4762306a36Sopenharmony_ci	unsigned long data;
4862306a36Sopenharmony_ci	unsigned long flags = 0;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (apmu->lock)
5162306a36Sopenharmony_ci		spin_lock_irqsave(apmu->lock, flags);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	data = readl_relaxed(apmu->base) & ~apmu->enable_mask;
5462306a36Sopenharmony_ci	writel_relaxed(data, apmu->base);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (apmu->lock)
5762306a36Sopenharmony_ci		spin_unlock_irqrestore(apmu->lock, flags);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic const struct clk_ops clk_apmu_ops = {
6162306a36Sopenharmony_ci	.enable = clk_apmu_enable,
6262306a36Sopenharmony_ci	.disable = clk_apmu_disable,
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct clk *mmp_clk_register_apmu(const char *name, const char *parent_name,
6662306a36Sopenharmony_ci		void __iomem *base, u32 enable_mask, spinlock_t *lock)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct clk_apmu *apmu;
6962306a36Sopenharmony_ci	struct clk *clk;
7062306a36Sopenharmony_ci	struct clk_init_data init;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	apmu = kzalloc(sizeof(*apmu), GFP_KERNEL);
7362306a36Sopenharmony_ci	if (!apmu)
7462306a36Sopenharmony_ci		return NULL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	init.name = name;
7762306a36Sopenharmony_ci	init.ops = &clk_apmu_ops;
7862306a36Sopenharmony_ci	init.flags = CLK_SET_RATE_PARENT;
7962306a36Sopenharmony_ci	init.parent_names = (parent_name ? &parent_name : NULL);
8062306a36Sopenharmony_ci	init.num_parents = (parent_name ? 1 : 0);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	apmu->base = base;
8362306a36Sopenharmony_ci	apmu->enable_mask = enable_mask;
8462306a36Sopenharmony_ci	apmu->lock = lock;
8562306a36Sopenharmony_ci	apmu->hw.init = &init;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	clk = clk_register(NULL, &apmu->hw);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (IS_ERR(clk))
9062306a36Sopenharmony_ci		kfree(apmu);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return clk;
9362306a36Sopenharmony_ci}
94