Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2015 Chen-Yu Tsai
0004  *
0005  * Chen-Yu Tsai <wens@csie.org>
0006  */
0007 
0008 #include <linux/clk-provider.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/reset-controller.h>
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015 
0016 static DEFINE_SPINLOCK(ve_lock);
0017 
0018 #define SUN4I_VE_ENABLE     31
0019 #define SUN4I_VE_DIVIDER_SHIFT  16
0020 #define SUN4I_VE_DIVIDER_WIDTH  3
0021 #define SUN4I_VE_RESET      0
0022 
0023 /*
0024  * sunxi_ve_reset... - reset bit in ve clk registers handling
0025  */
0026 
0027 struct ve_reset_data {
0028     void __iomem            *reg;
0029     spinlock_t          *lock;
0030     struct reset_controller_dev rcdev;
0031 };
0032 
0033 static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
0034                  unsigned long id)
0035 {
0036     struct ve_reset_data *data = container_of(rcdev,
0037                           struct ve_reset_data,
0038                           rcdev);
0039     unsigned long flags;
0040     u32 reg;
0041 
0042     spin_lock_irqsave(data->lock, flags);
0043 
0044     reg = readl(data->reg);
0045     writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
0046 
0047     spin_unlock_irqrestore(data->lock, flags);
0048 
0049     return 0;
0050 }
0051 
0052 static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
0053                    unsigned long id)
0054 {
0055     struct ve_reset_data *data = container_of(rcdev,
0056                           struct ve_reset_data,
0057                           rcdev);
0058     unsigned long flags;
0059     u32 reg;
0060 
0061     spin_lock_irqsave(data->lock, flags);
0062 
0063     reg = readl(data->reg);
0064     writel(reg | BIT(SUN4I_VE_RESET), data->reg);
0065 
0066     spin_unlock_irqrestore(data->lock, flags);
0067 
0068     return 0;
0069 }
0070 
0071 static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
0072                  const struct of_phandle_args *reset_spec)
0073 {
0074     if (WARN_ON(reset_spec->args_count != 0))
0075         return -EINVAL;
0076 
0077     return 0;
0078 }
0079 
0080 static const struct reset_control_ops sunxi_ve_reset_ops = {
0081     .assert     = sunxi_ve_reset_assert,
0082     .deassert   = sunxi_ve_reset_deassert,
0083 };
0084 
0085 static void __init sun4i_ve_clk_setup(struct device_node *node)
0086 {
0087     struct clk *clk;
0088     struct clk_divider *div;
0089     struct clk_gate *gate;
0090     struct ve_reset_data *reset_data;
0091     const char *parent;
0092     const char *clk_name = node->name;
0093     void __iomem *reg;
0094     int err;
0095 
0096     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0097     if (IS_ERR(reg))
0098         return;
0099 
0100     div = kzalloc(sizeof(*div), GFP_KERNEL);
0101     if (!div)
0102         goto err_unmap;
0103 
0104     gate = kzalloc(sizeof(*gate), GFP_KERNEL);
0105     if (!gate)
0106         goto err_free_div;
0107 
0108     of_property_read_string(node, "clock-output-names", &clk_name);
0109     parent = of_clk_get_parent_name(node, 0);
0110 
0111     gate->reg = reg;
0112     gate->bit_idx = SUN4I_VE_ENABLE;
0113     gate->lock = &ve_lock;
0114 
0115     div->reg = reg;
0116     div->shift = SUN4I_VE_DIVIDER_SHIFT;
0117     div->width = SUN4I_VE_DIVIDER_WIDTH;
0118     div->lock = &ve_lock;
0119 
0120     clk = clk_register_composite(NULL, clk_name, &parent, 1,
0121                      NULL, NULL,
0122                      &div->hw, &clk_divider_ops,
0123                      &gate->hw, &clk_gate_ops,
0124                      CLK_SET_RATE_PARENT);
0125     if (IS_ERR(clk))
0126         goto err_free_gate;
0127 
0128     err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
0129     if (err)
0130         goto err_unregister_clk;
0131 
0132     reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
0133     if (!reset_data)
0134         goto err_del_provider;
0135 
0136     reset_data->reg = reg;
0137     reset_data->lock = &ve_lock;
0138     reset_data->rcdev.nr_resets = 1;
0139     reset_data->rcdev.ops = &sunxi_ve_reset_ops;
0140     reset_data->rcdev.of_node = node;
0141     reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
0142     reset_data->rcdev.of_reset_n_cells = 0;
0143     err = reset_controller_register(&reset_data->rcdev);
0144     if (err)
0145         goto err_free_reset;
0146 
0147     return;
0148 
0149 err_free_reset:
0150     kfree(reset_data);
0151 err_del_provider:
0152     of_clk_del_provider(node);
0153 err_unregister_clk:
0154     clk_unregister(clk);
0155 err_free_gate:
0156     kfree(gate);
0157 err_free_div:
0158     kfree(div);
0159 err_unmap:
0160     iounmap(reg);
0161 }
0162 CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
0163            sun4i_ve_clk_setup);