Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  4 */
  5
  6#include <linux/clk-provider.h>
  7#include <linux/clkdev.h>
  8#include <linux/clk/at91_pmc.h>
  9#include <linux/of.h>
 10#include <linux/mfd/syscon.h>
 11#include <linux/regmap.h>
 12
 13#include "pmc.h"
 14
 15#define SYSTEM_MAX_ID		31
 16
 17#define SYSTEM_MAX_NAME_SZ	32
 18
 19#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
 20struct clk_system {
 21	struct clk_hw hw;
 22	struct regmap *regmap;
 23	u8 id;
 24};
 25
 26static inline int is_pck(int id)
 27{
 28	return (id >= 8) && (id <= 15);
 29}
 30
 31static inline bool clk_system_ready(struct regmap *regmap, int id)
 32{
 33	unsigned int status;
 34
 35	regmap_read(regmap, AT91_PMC_SR, &status);
 36
 37	return status & (1 << id) ? 1 : 0;
 38}
 39
 40static int clk_system_prepare(struct clk_hw *hw)
 41{
 42	struct clk_system *sys = to_clk_system(hw);
 43
 44	regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
 45
 46	if (!is_pck(sys->id))
 47		return 0;
 48
 49	while (!clk_system_ready(sys->regmap, sys->id))
 50		cpu_relax();
 51
 52	return 0;
 53}
 54
 55static void clk_system_unprepare(struct clk_hw *hw)
 56{
 57	struct clk_system *sys = to_clk_system(hw);
 58
 59	regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
 60}
 61
 62static int clk_system_is_prepared(struct clk_hw *hw)
 63{
 64	struct clk_system *sys = to_clk_system(hw);
 65	unsigned int status;
 66
 67	regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
 68
 69	if (!(status & (1 << sys->id)))
 70		return 0;
 71
 72	if (!is_pck(sys->id))
 73		return 1;
 74
 75	regmap_read(sys->regmap, AT91_PMC_SR, &status);
 76
 77	return status & (1 << sys->id) ? 1 : 0;
 78}
 79
 80static const struct clk_ops system_ops = {
 81	.prepare = clk_system_prepare,
 82	.unprepare = clk_system_unprepare,
 83	.is_prepared = clk_system_is_prepared,
 84};
 85
 86struct clk_hw * __init
 87at91_clk_register_system(struct regmap *regmap, const char *name,
 88			 const char *parent_name, u8 id)
 89{
 90	struct clk_system *sys;
 91	struct clk_hw *hw;
 92	struct clk_init_data init;
 93	int ret;
 94
 95	if (!parent_name || id > SYSTEM_MAX_ID)
 96		return ERR_PTR(-EINVAL);
 97
 98	sys = kzalloc(sizeof(*sys), GFP_KERNEL);
 99	if (!sys)
100		return ERR_PTR(-ENOMEM);
101
102	init.name = name;
103	init.ops = &system_ops;
104	init.parent_names = &parent_name;
105	init.num_parents = 1;
106	init.flags = CLK_SET_RATE_PARENT;
107
108	sys->id = id;
109	sys->hw.init = &init;
110	sys->regmap = regmap;
111
112	hw = &sys->hw;
113	ret = clk_hw_register(NULL, &sys->hw);
114	if (ret) {
115		kfree(sys);
116		hw = ERR_PTR(ret);
117	}
118
119	return hw;
120}