brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 6581093 Raw
164 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2015 Chen-Yu Tsai4 *5 * Chen-Yu Tsai <wens@csie.org>6 */7 8#include <linux/clk-provider.h>9#include <linux/io.h>10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/reset-controller.h>13#include <linux/slab.h>14#include <linux/spinlock.h>15 16static DEFINE_SPINLOCK(ve_lock);17 18#define SUN4I_VE_ENABLE		3119#define SUN4I_VE_DIVIDER_SHIFT	1620#define SUN4I_VE_DIVIDER_WIDTH	321#define SUN4I_VE_RESET		022 23/*24 * sunxi_ve_reset... - reset bit in ve clk registers handling25 */26 27struct ve_reset_data {28	void __iomem			*reg;29	spinlock_t			*lock;30	struct reset_controller_dev	rcdev;31};32 33static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,34				 unsigned long id)35{36	struct ve_reset_data *data = container_of(rcdev,37						  struct ve_reset_data,38						  rcdev);39	unsigned long flags;40	u32 reg;41 42	spin_lock_irqsave(data->lock, flags);43 44	reg = readl(data->reg);45	writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);46 47	spin_unlock_irqrestore(data->lock, flags);48 49	return 0;50}51 52static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,53				   unsigned long id)54{55	struct ve_reset_data *data = container_of(rcdev,56						  struct ve_reset_data,57						  rcdev);58	unsigned long flags;59	u32 reg;60 61	spin_lock_irqsave(data->lock, flags);62 63	reg = readl(data->reg);64	writel(reg | BIT(SUN4I_VE_RESET), data->reg);65 66	spin_unlock_irqrestore(data->lock, flags);67 68	return 0;69}70 71static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,72			     const struct of_phandle_args *reset_spec)73{74	if (WARN_ON(reset_spec->args_count != 0))75		return -EINVAL;76 77	return 0;78}79 80static const struct reset_control_ops sunxi_ve_reset_ops = {81	.assert		= sunxi_ve_reset_assert,82	.deassert	= sunxi_ve_reset_deassert,83};84 85static void __init sun4i_ve_clk_setup(struct device_node *node)86{87	struct clk *clk;88	struct clk_divider *div;89	struct clk_gate *gate;90	struct ve_reset_data *reset_data;91	const char *parent;92	const char *clk_name = node->name;93	void __iomem *reg;94	int err;95 96	reg = of_io_request_and_map(node, 0, of_node_full_name(node));97	if (IS_ERR(reg))98		return;99 100	div = kzalloc(sizeof(*div), GFP_KERNEL);101	if (!div)102		goto err_unmap;103 104	gate = kzalloc(sizeof(*gate), GFP_KERNEL);105	if (!gate)106		goto err_free_div;107 108	of_property_read_string(node, "clock-output-names", &clk_name);109	parent = of_clk_get_parent_name(node, 0);110 111	gate->reg = reg;112	gate->bit_idx = SUN4I_VE_ENABLE;113	gate->lock = &ve_lock;114 115	div->reg = reg;116	div->shift = SUN4I_VE_DIVIDER_SHIFT;117	div->width = SUN4I_VE_DIVIDER_WIDTH;118	div->lock = &ve_lock;119 120	clk = clk_register_composite(NULL, clk_name, &parent, 1,121				     NULL, NULL,122				     &div->hw, &clk_divider_ops,123				     &gate->hw, &clk_gate_ops,124				     CLK_SET_RATE_PARENT);125	if (IS_ERR(clk))126		goto err_free_gate;127 128	err = of_clk_add_provider(node, of_clk_src_simple_get, clk);129	if (err)130		goto err_unregister_clk;131 132	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);133	if (!reset_data)134		goto err_del_provider;135 136	reset_data->reg = reg;137	reset_data->lock = &ve_lock;138	reset_data->rcdev.nr_resets = 1;139	reset_data->rcdev.ops = &sunxi_ve_reset_ops;140	reset_data->rcdev.of_node = node;141	reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;142	reset_data->rcdev.of_reset_n_cells = 0;143	err = reset_controller_register(&reset_data->rcdev);144	if (err)145		goto err_free_reset;146 147	return;148 149err_free_reset:150	kfree(reset_data);151err_del_provider:152	of_clk_del_provider(node);153err_unregister_clk:154	clk_unregister(clk);155err_free_gate:156	kfree(gate);157err_free_div:158	kfree(div);159err_unmap:160	iounmap(reg);161}162CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",163	       sun4i_ve_clk_setup);164