Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Copyright (C) 2013 ARM Limited
  5 */
  6
  7#include <linux/amba/sp810.h>
  8#include <linux/slab.h>
  9#include <linux/clk.h>
 10#include <linux/clk-provider.h>
 11#include <linux/err.h>
 12#include <linux/io.h>
 13#include <linux/of.h>
 14#include <linux/of_address.h>
 15
 16#define to_clk_sp810_timerclken(_hw) \
 17		container_of(_hw, struct clk_sp810_timerclken, hw)
 18
 19struct clk_sp810;
 20
 21struct clk_sp810_timerclken {
 22	struct clk_hw hw;
 23	struct clk *clk;
 24	struct clk_sp810 *sp810;
 25	int channel;
 26};
 27
 28struct clk_sp810 {
 29	struct device_node *node;
 30	void __iomem *base;
 31	spinlock_t lock;
 32	struct clk_sp810_timerclken timerclken[4];
 33};
 34
 35static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw)
 36{
 37	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 38	u32 val = readl(timerclken->sp810->base + SCCTRL);
 39
 40	return !!(val & (1 << SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel)));
 41}
 42
 43static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index)
 44{
 45	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 46	struct clk_sp810 *sp810 = timerclken->sp810;
 47	u32 val, shift = SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel);
 48	unsigned long flags = 0;
 49
 50	if (WARN_ON(index > 1))
 51		return -EINVAL;
 52
 53	spin_lock_irqsave(&sp810->lock, flags);
 54
 55	val = readl(sp810->base + SCCTRL);
 56	val &= ~(1 << shift);
 57	val |= index << shift;
 58	writel(val, sp810->base + SCCTRL);
 59
 60	spin_unlock_irqrestore(&sp810->lock, flags);
 61
 62	return 0;
 63}
 64
 65static const struct clk_ops clk_sp810_timerclken_ops = {
 66	.determine_rate = clk_hw_determine_rate_no_reparent,
 67	.get_parent = clk_sp810_timerclken_get_parent,
 68	.set_parent = clk_sp810_timerclken_set_parent,
 69};
 70
 71static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
 72		void *data)
 73{
 74	struct clk_sp810 *sp810 = data;
 75
 76	if (WARN_ON(clkspec->args_count != 1 ||
 77		    clkspec->args[0] >=	ARRAY_SIZE(sp810->timerclken)))
 78		return NULL;
 79
 80	return sp810->timerclken[clkspec->args[0]].clk;
 81}
 82
 83static void __init clk_sp810_of_setup(struct device_node *node)
 84{
 85	struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
 86	const char *parent_names[2];
 87	int num = ARRAY_SIZE(parent_names);
 88	char name[12];
 89	struct clk_init_data init;
 90	static int instance;
 91	int i;
 92	bool deprecated;
 93
 94	if (!sp810)
 95		return;
 96
 97	if (of_clk_parent_fill(node, parent_names, num) != num) {
 98		pr_warn("Failed to obtain parent clocks for SP810!\n");
 99		kfree(sp810);
100		return;
101	}
102
103	sp810->node = node;
104	sp810->base = of_iomap(node, 0);
105	spin_lock_init(&sp810->lock);
106
107	init.name = name;
108	init.ops = &clk_sp810_timerclken_ops;
109	init.flags = 0;
110	init.parent_names = parent_names;
111	init.num_parents = num;
112
113	deprecated = !of_property_present(node, "assigned-clock-parents");
114
115	for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
116		snprintf(name, sizeof(name), "sp810_%d_%d", instance, i);
117
118		sp810->timerclken[i].sp810 = sp810;
119		sp810->timerclken[i].channel = i;
120		sp810->timerclken[i].hw.init = &init;
121
122		/*
123		 * If DT isn't setting the parent, force it to be
124		 * the 1 MHz clock without going through the framework.
125		 * We do this before clk_register() so that it can determine
126		 * the parent and setup the tree properly.
127		 */
128		if (deprecated)
129			init.ops->set_parent(&sp810->timerclken[i].hw, 1);
130
131		sp810->timerclken[i].clk = clk_register(NULL,
132				&sp810->timerclken[i].hw);
133		WARN_ON(IS_ERR(sp810->timerclken[i].clk));
134	}
135
136	of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
137	instance++;
138}
139CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Copyright (C) 2013 ARM Limited
  5 */
  6
  7#include <linux/amba/sp810.h>
  8#include <linux/slab.h>
  9#include <linux/clk.h>
 10#include <linux/clk-provider.h>
 11#include <linux/err.h>
 12#include <linux/io.h>
 13#include <linux/of.h>
 14#include <linux/of_address.h>
 15
 16#define to_clk_sp810_timerclken(_hw) \
 17		container_of(_hw, struct clk_sp810_timerclken, hw)
 18
 19struct clk_sp810;
 20
 21struct clk_sp810_timerclken {
 22	struct clk_hw hw;
 23	struct clk *clk;
 24	struct clk_sp810 *sp810;
 25	int channel;
 26};
 27
 28struct clk_sp810 {
 29	struct device_node *node;
 30	void __iomem *base;
 31	spinlock_t lock;
 32	struct clk_sp810_timerclken timerclken[4];
 33};
 34
 35static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw)
 36{
 37	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 38	u32 val = readl(timerclken->sp810->base + SCCTRL);
 39
 40	return !!(val & (1 << SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel)));
 41}
 42
 43static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index)
 44{
 45	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 46	struct clk_sp810 *sp810 = timerclken->sp810;
 47	u32 val, shift = SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel);
 48	unsigned long flags = 0;
 49
 50	if (WARN_ON(index > 1))
 51		return -EINVAL;
 52
 53	spin_lock_irqsave(&sp810->lock, flags);
 54
 55	val = readl(sp810->base + SCCTRL);
 56	val &= ~(1 << shift);
 57	val |= index << shift;
 58	writel(val, sp810->base + SCCTRL);
 59
 60	spin_unlock_irqrestore(&sp810->lock, flags);
 61
 62	return 0;
 63}
 64
 65static const struct clk_ops clk_sp810_timerclken_ops = {
 
 66	.get_parent = clk_sp810_timerclken_get_parent,
 67	.set_parent = clk_sp810_timerclken_set_parent,
 68};
 69
 70static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
 71		void *data)
 72{
 73	struct clk_sp810 *sp810 = data;
 74
 75	if (WARN_ON(clkspec->args_count != 1 ||
 76		    clkspec->args[0] >=	ARRAY_SIZE(sp810->timerclken)))
 77		return NULL;
 78
 79	return sp810->timerclken[clkspec->args[0]].clk;
 80}
 81
 82static void __init clk_sp810_of_setup(struct device_node *node)
 83{
 84	struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
 85	const char *parent_names[2];
 86	int num = ARRAY_SIZE(parent_names);
 87	char name[12];
 88	struct clk_init_data init;
 89	static int instance;
 90	int i;
 91	bool deprecated;
 92
 93	if (!sp810)
 94		return;
 95
 96	if (of_clk_parent_fill(node, parent_names, num) != num) {
 97		pr_warn("Failed to obtain parent clocks for SP810!\n");
 98		kfree(sp810);
 99		return;
100	}
101
102	sp810->node = node;
103	sp810->base = of_iomap(node, 0);
104	spin_lock_init(&sp810->lock);
105
106	init.name = name;
107	init.ops = &clk_sp810_timerclken_ops;
108	init.flags = 0;
109	init.parent_names = parent_names;
110	init.num_parents = num;
111
112	deprecated = !of_find_property(node, "assigned-clock-parents", NULL);
113
114	for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
115		snprintf(name, sizeof(name), "sp810_%d_%d", instance, i);
116
117		sp810->timerclken[i].sp810 = sp810;
118		sp810->timerclken[i].channel = i;
119		sp810->timerclken[i].hw.init = &init;
120
121		/*
122		 * If DT isn't setting the parent, force it to be
123		 * the 1 MHz clock without going through the framework.
124		 * We do this before clk_register() so that it can determine
125		 * the parent and setup the tree properly.
126		 */
127		if (deprecated)
128			init.ops->set_parent(&sp810->timerclken[i].hw, 1);
129
130		sp810->timerclken[i].clk = clk_register(NULL,
131				&sp810->timerclken[i].hw);
132		WARN_ON(IS_ERR(sp810->timerclken[i].clk));
133	}
134
135	of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
136	instance++;
137}
138CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);