hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2014 Freescale Semiconductor, Inc.
 */
 
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "clk.h"
 
/**
 * struct clk_gate_exclusive - i.MX specific gate clock which is mutually
 * exclusive with other gate clocks
 *
 * @gate: the parent class
 * @exclusive_mask: mask of gate bits which are mutually exclusive to this
 *    gate clock
 *
 * The imx exclusive gate clock is a subclass of basic clk_gate
 * with an addtional mask to indicate which other gate bits in the same
 * register is mutually exclusive to this gate clock.
 */
struct clk_gate_exclusive {
   struct clk_gate gate;
   u32 exclusive_mask;
};
 
static int clk_gate_exclusive_enable(struct clk_hw *hw)
{
   struct clk_gate *gate = to_clk_gate(hw);
   struct clk_gate_exclusive *exgate = container_of(gate,
                   struct clk_gate_exclusive, gate);
   u32 val = readl(gate->reg);
 
   if (val & exgate->exclusive_mask)
       return -EBUSY;
 
   return clk_gate_ops.enable(hw);
}
 
static void clk_gate_exclusive_disable(struct clk_hw *hw)
{
   clk_gate_ops.disable(hw);
}
 
static int clk_gate_exclusive_is_enabled(struct clk_hw *hw)
{
   return clk_gate_ops.is_enabled(hw);
}
 
static const struct clk_ops clk_gate_exclusive_ops = {
   .enable = clk_gate_exclusive_enable,
   .disable = clk_gate_exclusive_disable,
   .is_enabled = clk_gate_exclusive_is_enabled,
};
 
struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
    void __iomem *reg, u8 shift, u32 exclusive_mask)
{
   struct clk_gate_exclusive *exgate;
   struct clk_gate *gate;
   struct clk_hw *hw;
   struct clk_init_data init;
   int ret;
 
   if (exclusive_mask == 0)
       return ERR_PTR(-EINVAL);
 
   exgate = kzalloc(sizeof(*exgate), GFP_KERNEL);
   if (!exgate)
       return ERR_PTR(-ENOMEM);
   gate = &exgate->gate;
 
   init.name = name;
   init.ops = &clk_gate_exclusive_ops;
   init.flags = CLK_SET_RATE_PARENT;
   init.parent_names = parent ? &parent : NULL;
   init.num_parents = parent ? 1 : 0;
 
   gate->reg = reg;
   gate->bit_idx = shift;
   gate->lock = &imx_ccm_lock;
   gate->hw.init = &init;
   exgate->exclusive_mask = exclusive_mask;
 
   hw = &gate->hw;
 
   ret = clk_hw_register(NULL, hw);
   if (ret) {
       kfree(gate);
       return ERR_PTR(ret);
   }
 
   return hw;
}