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