Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.5-rc7 171 lines 4.1 kB view raw
1/* 2 * Copyright 2015 Chen-Yu Tsai 3 * 4 * Chen-Yu Tsai <wens@csie.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/clk-provider.h> 18#include <linux/of.h> 19#include <linux/of_address.h> 20#include <linux/reset-controller.h> 21#include <linux/slab.h> 22#include <linux/spinlock.h> 23 24static DEFINE_SPINLOCK(ve_lock); 25 26#define SUN4I_VE_ENABLE 31 27#define SUN4I_VE_DIVIDER_SHIFT 16 28#define SUN4I_VE_DIVIDER_WIDTH 3 29#define SUN4I_VE_RESET 0 30 31/** 32 * sunxi_ve_reset... - reset bit in ve clk registers handling 33 */ 34 35struct ve_reset_data { 36 void __iomem *reg; 37 spinlock_t *lock; 38 struct reset_controller_dev rcdev; 39}; 40 41static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev, 42 unsigned long id) 43{ 44 struct ve_reset_data *data = container_of(rcdev, 45 struct ve_reset_data, 46 rcdev); 47 unsigned long flags; 48 u32 reg; 49 50 spin_lock_irqsave(data->lock, flags); 51 52 reg = readl(data->reg); 53 writel(reg & ~BIT(SUN4I_VE_RESET), data->reg); 54 55 spin_unlock_irqrestore(data->lock, flags); 56 57 return 0; 58} 59 60static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev, 61 unsigned long id) 62{ 63 struct ve_reset_data *data = container_of(rcdev, 64 struct ve_reset_data, 65 rcdev); 66 unsigned long flags; 67 u32 reg; 68 69 spin_lock_irqsave(data->lock, flags); 70 71 reg = readl(data->reg); 72 writel(reg | BIT(SUN4I_VE_RESET), data->reg); 73 74 spin_unlock_irqrestore(data->lock, flags); 75 76 return 0; 77} 78 79static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev, 80 const struct of_phandle_args *reset_spec) 81{ 82 if (WARN_ON(reset_spec->args_count != 0)) 83 return -EINVAL; 84 85 return 0; 86} 87 88static struct reset_control_ops sunxi_ve_reset_ops = { 89 .assert = sunxi_ve_reset_assert, 90 .deassert = sunxi_ve_reset_deassert, 91}; 92 93static void __init sun4i_ve_clk_setup(struct device_node *node) 94{ 95 struct clk *clk; 96 struct clk_divider *div; 97 struct clk_gate *gate; 98 struct ve_reset_data *reset_data; 99 const char *parent; 100 const char *clk_name = node->name; 101 void __iomem *reg; 102 int err; 103 104 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 105 if (IS_ERR(reg)) 106 return; 107 108 div = kzalloc(sizeof(*div), GFP_KERNEL); 109 if (!div) 110 goto err_unmap; 111 112 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 113 if (!gate) 114 goto err_free_div; 115 116 of_property_read_string(node, "clock-output-names", &clk_name); 117 parent = of_clk_get_parent_name(node, 0); 118 119 gate->reg = reg; 120 gate->bit_idx = SUN4I_VE_ENABLE; 121 gate->lock = &ve_lock; 122 123 div->reg = reg; 124 div->shift = SUN4I_VE_DIVIDER_SHIFT; 125 div->width = SUN4I_VE_DIVIDER_WIDTH; 126 div->lock = &ve_lock; 127 128 clk = clk_register_composite(NULL, clk_name, &parent, 1, 129 NULL, NULL, 130 &div->hw, &clk_divider_ops, 131 &gate->hw, &clk_gate_ops, 132 CLK_SET_RATE_PARENT); 133 if (IS_ERR(clk)) 134 goto err_free_gate; 135 136 err = of_clk_add_provider(node, of_clk_src_simple_get, clk); 137 if (err) 138 goto err_unregister_clk; 139 140 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); 141 if (!reset_data) 142 goto err_del_provider; 143 144 reset_data->reg = reg; 145 reset_data->lock = &ve_lock; 146 reset_data->rcdev.nr_resets = 1; 147 reset_data->rcdev.ops = &sunxi_ve_reset_ops; 148 reset_data->rcdev.of_node = node; 149 reset_data->rcdev.of_xlate = sunxi_ve_of_xlate; 150 reset_data->rcdev.of_reset_n_cells = 0; 151 err = reset_controller_register(&reset_data->rcdev); 152 if (err) 153 goto err_free_reset; 154 155 return; 156 157err_free_reset: 158 kfree(reset_data); 159err_del_provider: 160 of_clk_del_provider(node); 161err_unregister_clk: 162 clk_unregister(clk); 163err_free_gate: 164 kfree(gate); 165err_free_div: 166 kfree(div); 167err_unmap: 168 iounmap(reg); 169} 170CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk", 171 sun4i_ve_clk_setup);