linux/drivers/clk/imx/clk-gate-exclusive.c
<<
>>
Prefs
   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 */
  27struct clk_gate_exclusive {
  28        struct clk_gate gate;
  29        u32 exclusive_mask;
  30};
  31
  32static int clk_gate_exclusive_enable(struct clk_hw *hw)
  33{
  34        struct clk_gate *gate = to_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
  45static void clk_gate_exclusive_disable(struct clk_hw *hw)
  46{
  47        clk_gate_ops.disable(hw);
  48}
  49
  50static int clk_gate_exclusive_is_enabled(struct clk_hw *hw)
  51{
  52        return clk_gate_ops.is_enabled(hw);
  53}
  54
  55static 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
  61struct 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