Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2014 Freescale Semiconductor, Inc.
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/slab.h>
0010 #include "clk.h"
0011 
0012 /**
0013  * struct clk_gate_exclusive - i.MX specific gate clock which is mutually
0014  * exclusive with other gate clocks
0015  *
0016  * @gate: the parent class
0017  * @exclusive_mask: mask of gate bits which are mutually exclusive to this
0018  *  gate clock
0019  *
0020  * The imx exclusive gate clock is a subclass of basic clk_gate
0021  * with an addtional mask to indicate which other gate bits in the same
0022  * register is mutually exclusive to this gate clock.
0023  */
0024 struct clk_gate_exclusive {
0025     struct clk_gate gate;
0026     u32 exclusive_mask;
0027 };
0028 
0029 static int clk_gate_exclusive_enable(struct clk_hw *hw)
0030 {
0031     struct clk_gate *gate = to_clk_gate(hw);
0032     struct clk_gate_exclusive *exgate = container_of(gate,
0033                     struct clk_gate_exclusive, gate);
0034     u32 val = readl(gate->reg);
0035 
0036     if (val & exgate->exclusive_mask)
0037         return -EBUSY;
0038 
0039     return clk_gate_ops.enable(hw);
0040 }
0041 
0042 static void clk_gate_exclusive_disable(struct clk_hw *hw)
0043 {
0044     clk_gate_ops.disable(hw);
0045 }
0046 
0047 static int clk_gate_exclusive_is_enabled(struct clk_hw *hw)
0048 {
0049     return clk_gate_ops.is_enabled(hw);
0050 }
0051 
0052 static const struct clk_ops clk_gate_exclusive_ops = {
0053     .enable = clk_gate_exclusive_enable,
0054     .disable = clk_gate_exclusive_disable,
0055     .is_enabled = clk_gate_exclusive_is_enabled,
0056 };
0057 
0058 struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
0059      void __iomem *reg, u8 shift, u32 exclusive_mask)
0060 {
0061     struct clk_gate_exclusive *exgate;
0062     struct clk_gate *gate;
0063     struct clk_hw *hw;
0064     struct clk_init_data init;
0065     int ret;
0066 
0067     if (exclusive_mask == 0)
0068         return ERR_PTR(-EINVAL);
0069 
0070     exgate = kzalloc(sizeof(*exgate), GFP_KERNEL);
0071     if (!exgate)
0072         return ERR_PTR(-ENOMEM);
0073     gate = &exgate->gate;
0074 
0075     init.name = name;
0076     init.ops = &clk_gate_exclusive_ops;
0077     init.flags = CLK_SET_RATE_PARENT;
0078     init.parent_names = parent ? &parent : NULL;
0079     init.num_parents = parent ? 1 : 0;
0080 
0081     gate->reg = reg;
0082     gate->bit_idx = shift;
0083     gate->lock = &imx_ccm_lock;
0084     gate->hw.init = &init;
0085     exgate->exclusive_mask = exclusive_mask;
0086 
0087     hw = &gate->hw;
0088 
0089     ret = clk_hw_register(NULL, hw);
0090     if (ret) {
0091         kfree(gate);
0092         return ERR_PTR(ret);
0093     }
0094 
0095     return hw;
0096 }