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