Linux Audio

Check our new training course

Loading...
v6.2
  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	struct at91_clk_pms pms;
 24	u8 id;
 25};
 26
 27static inline int is_pck(int id)
 28{
 29	return (id >= 8) && (id <= 15);
 30}
 31
 32static inline bool clk_system_ready(struct regmap *regmap, int id)
 33{
 34	unsigned int status;
 35
 36	regmap_read(regmap, AT91_PMC_SR, &status);
 37
 38	return !!(status & (1 << id));
 39}
 40
 41static int clk_system_prepare(struct clk_hw *hw)
 42{
 43	struct clk_system *sys = to_clk_system(hw);
 44
 45	regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
 46
 47	if (!is_pck(sys->id))
 48		return 0;
 49
 50	while (!clk_system_ready(sys->regmap, sys->id))
 51		cpu_relax();
 52
 53	return 0;
 54}
 55
 56static void clk_system_unprepare(struct clk_hw *hw)
 57{
 58	struct clk_system *sys = to_clk_system(hw);
 59
 60	regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
 61}
 62
 63static int clk_system_is_prepared(struct clk_hw *hw)
 64{
 65	struct clk_system *sys = to_clk_system(hw);
 66	unsigned int status;
 67
 68	regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
 69
 70	if (!(status & (1 << sys->id)))
 71		return 0;
 72
 73	if (!is_pck(sys->id))
 74		return 1;
 75
 76	regmap_read(sys->regmap, AT91_PMC_SR, &status);
 77
 78	return !!(status & (1 << sys->id));
 79}
 80
 81static int clk_system_save_context(struct clk_hw *hw)
 82{
 83	struct clk_system *sys = to_clk_system(hw);
 84
 85	sys->pms.status = clk_system_is_prepared(hw);
 86
 87	return 0;
 88}
 89
 90static void clk_system_restore_context(struct clk_hw *hw)
 91{
 92	struct clk_system *sys = to_clk_system(hw);
 93
 94	if (sys->pms.status)
 95		clk_system_prepare(&sys->hw);
 96}
 97
 98static const struct clk_ops system_ops = {
 99	.prepare = clk_system_prepare,
100	.unprepare = clk_system_unprepare,
101	.is_prepared = clk_system_is_prepared,
102	.save_context = clk_system_save_context,
103	.restore_context = clk_system_restore_context,
104};
105
106struct clk_hw * __init
107at91_clk_register_system(struct regmap *regmap, const char *name,
108			 const char *parent_name, u8 id)
109{
110	struct clk_system *sys;
111	struct clk_hw *hw;
112	struct clk_init_data init;
113	int ret;
114
115	if (!parent_name || id > SYSTEM_MAX_ID)
116		return ERR_PTR(-EINVAL);
117
118	sys = kzalloc(sizeof(*sys), GFP_KERNEL);
119	if (!sys)
120		return ERR_PTR(-ENOMEM);
121
122	init.name = name;
123	init.ops = &system_ops;
124	init.parent_names = &parent_name;
125	init.num_parents = 1;
126	init.flags = CLK_SET_RATE_PARENT;
127
128	sys->id = id;
129	sys->hw.init = &init;
130	sys->regmap = regmap;
131
132	hw = &sys->hw;
133	ret = clk_hw_register(NULL, &sys->hw);
134	if (ret) {
135		kfree(sys);
136		hw = ERR_PTR(ret);
137	}
138
139	return hw;
140}
v5.4
  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}