brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 23c43a4 Raw
149 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mmp APB clock operation source file4 *5 * Copyright (C) 2012 Marvell6 * Chao Xie <xiechao.mail@gmail.com>7 */8 9#include <linux/kernel.h>10#include <linux/io.h>11#include <linux/err.h>12#include <linux/delay.h>13#include <linux/slab.h>14 15#include "clk.h"16 17/* Common APB clock register bit definitions */18#define APBC_APBCLK	(1 << 0)  /* APB Bus Clock Enable */19#define APBC_FNCLK	(1 << 1)  /* Functional Clock Enable */20#define APBC_RST	(1 << 2)  /* Reset Generation */21#define APBC_POWER	(1 << 7)  /* Reset Generation */22 23#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)24struct clk_apbc {25	struct clk_hw		hw;26	void __iomem		*base;27	unsigned int		delay;28	unsigned int		flags;29	spinlock_t		*lock;30};31 32static int clk_apbc_prepare(struct clk_hw *hw)33{34	struct clk_apbc *apbc = to_clk_apbc(hw);35	unsigned int data;36	unsigned long flags = 0;37 38	/*39	 * It may share same register as MUX clock,40	 * and it will impact FNCLK enable. Spinlock is needed41	 */42	if (apbc->lock)43		spin_lock_irqsave(apbc->lock, flags);44 45	data = readl_relaxed(apbc->base);46	if (apbc->flags & APBC_POWER_CTRL)47		data |= APBC_POWER;48	data |= APBC_FNCLK;49	writel_relaxed(data, apbc->base);50 51	if (apbc->lock)52		spin_unlock_irqrestore(apbc->lock, flags);53 54	udelay(apbc->delay);55 56	if (apbc->lock)57		spin_lock_irqsave(apbc->lock, flags);58 59	data = readl_relaxed(apbc->base);60	data |= APBC_APBCLK;61	writel_relaxed(data, apbc->base);62 63	if (apbc->lock)64		spin_unlock_irqrestore(apbc->lock, flags);65 66	udelay(apbc->delay);67 68	if (!(apbc->flags & APBC_NO_BUS_CTRL)) {69		if (apbc->lock)70			spin_lock_irqsave(apbc->lock, flags);71 72		data = readl_relaxed(apbc->base);73		data &= ~APBC_RST;74		writel_relaxed(data, apbc->base);75 76		if (apbc->lock)77			spin_unlock_irqrestore(apbc->lock, flags);78	}79 80	return 0;81}82 83static void clk_apbc_unprepare(struct clk_hw *hw)84{85	struct clk_apbc *apbc = to_clk_apbc(hw);86	unsigned long data;87	unsigned long flags = 0;88 89	if (apbc->lock)90		spin_lock_irqsave(apbc->lock, flags);91 92	data = readl_relaxed(apbc->base);93	if (apbc->flags & APBC_POWER_CTRL)94		data &= ~APBC_POWER;95	data &= ~APBC_FNCLK;96	writel_relaxed(data, apbc->base);97 98	if (apbc->lock)99		spin_unlock_irqrestore(apbc->lock, flags);100 101	udelay(10);102 103	if (apbc->lock)104		spin_lock_irqsave(apbc->lock, flags);105 106	data = readl_relaxed(apbc->base);107	data &= ~APBC_APBCLK;108	writel_relaxed(data, apbc->base);109 110	if (apbc->lock)111		spin_unlock_irqrestore(apbc->lock, flags);112}113 114static const struct clk_ops clk_apbc_ops = {115	.prepare = clk_apbc_prepare,116	.unprepare = clk_apbc_unprepare,117};118 119struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,120		void __iomem *base, unsigned int delay,121		unsigned int apbc_flags, spinlock_t *lock)122{123	struct clk_apbc *apbc;124	struct clk *clk;125	struct clk_init_data init;126 127	apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);128	if (!apbc)129		return NULL;130 131	init.name = name;132	init.ops = &clk_apbc_ops;133	init.flags = CLK_SET_RATE_PARENT;134	init.parent_names = (parent_name ? &parent_name : NULL);135	init.num_parents = (parent_name ? 1 : 0);136 137	apbc->base = base;138	apbc->delay = delay;139	apbc->flags = apbc_flags;140	apbc->lock = lock;141	apbc->hw.init = &init;142 143	clk = clk_register(NULL, &apbc->hw);144	if (IS_ERR(clk))145		kfree(apbc);146 147	return clk;148}149