root/drivers/clk/ti/autoidle.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _omap2_clk_deny_idle
  2. _omap2_clk_allow_idle
  3. omap2_clk_deny_idle
  4. omap2_clk_allow_idle
  5. _allow_autoidle
  6. _deny_autoidle
  7. _clk_generic_allow_autoidle_all
  8. _clk_generic_deny_autoidle_all
  9. of_ti_clk_autoidle_setup
  10. omap2_clk_enable_autoidle_all
  11. omap2_clk_disable_autoidle_all

   1 /*
   2  * TI clock autoidle support
   3  *
   4  * Copyright (C) 2013 Texas Instruments, Inc.
   5  *
   6  * Tero Kristo <t-kristo@ti.com>
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License version 2 as
  10  * published by the Free Software Foundation.
  11  *
  12  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13  * kind, whether express or implied; without even the implied warranty
  14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  */
  17 
  18 #include <linux/clk-provider.h>
  19 #include <linux/slab.h>
  20 #include <linux/io.h>
  21 #include <linux/of.h>
  22 #include <linux/of_address.h>
  23 #include <linux/clk/ti.h>
  24 
  25 #include "clock.h"
  26 
  27 struct clk_ti_autoidle {
  28         struct clk_omap_reg     reg;
  29         u8                      shift;
  30         u8                      flags;
  31         const char              *name;
  32         struct list_head        node;
  33 };
  34 
  35 #define AUTOIDLE_LOW            0x1
  36 
  37 static LIST_HEAD(autoidle_clks);
  38 
  39 /*
  40  * we have some non-atomic read/write
  41  * operations behind it, so lets
  42  * take one lock for handling autoidle
  43  * of all clocks
  44  */
  45 static DEFINE_SPINLOCK(autoidle_spinlock);
  46 
  47 static int _omap2_clk_deny_idle(struct clk_hw_omap *clk)
  48 {
  49         if (clk->ops && clk->ops->deny_idle) {
  50                 unsigned long irqflags;
  51 
  52                 spin_lock_irqsave(&autoidle_spinlock, irqflags);
  53                 clk->autoidle_count++;
  54                 if (clk->autoidle_count == 1)
  55                         clk->ops->deny_idle(clk);
  56 
  57                 spin_unlock_irqrestore(&autoidle_spinlock, irqflags);
  58         }
  59         return 0;
  60 }
  61 
  62 static int _omap2_clk_allow_idle(struct clk_hw_omap *clk)
  63 {
  64         if (clk->ops && clk->ops->allow_idle) {
  65                 unsigned long irqflags;
  66 
  67                 spin_lock_irqsave(&autoidle_spinlock, irqflags);
  68                 clk->autoidle_count--;
  69                 if (clk->autoidle_count == 0)
  70                         clk->ops->allow_idle(clk);
  71 
  72                 spin_unlock_irqrestore(&autoidle_spinlock, irqflags);
  73         }
  74         return 0;
  75 }
  76 
  77 /**
  78  * omap2_clk_deny_idle - disable autoidle on an OMAP clock
  79  * @clk: struct clk * to disable autoidle for
  80  *
  81  * Disable autoidle on an OMAP clock.
  82  */
  83 int omap2_clk_deny_idle(struct clk *clk)
  84 {
  85         struct clk_hw *hw = __clk_get_hw(clk);
  86 
  87         if (omap2_clk_is_hw_omap(hw)) {
  88                 struct clk_hw_omap *c = to_clk_hw_omap(hw);
  89 
  90                 return _omap2_clk_deny_idle(c);
  91         }
  92 
  93         return -EINVAL;
  94 }
  95 
  96 /**
  97  * omap2_clk_allow_idle - enable autoidle on an OMAP clock
  98  * @clk: struct clk * to enable autoidle for
  99  *
 100  * Enable autoidle on an OMAP clock.
 101  */
 102 int omap2_clk_allow_idle(struct clk *clk)
 103 {
 104         struct clk_hw *hw = __clk_get_hw(clk);
 105 
 106         if (omap2_clk_is_hw_omap(hw)) {
 107                 struct clk_hw_omap *c = to_clk_hw_omap(hw);
 108 
 109                 return _omap2_clk_allow_idle(c);
 110         }
 111 
 112         return -EINVAL;
 113 }
 114 
 115 static void _allow_autoidle(struct clk_ti_autoidle *clk)
 116 {
 117         u32 val;
 118 
 119         val = ti_clk_ll_ops->clk_readl(&clk->reg);
 120 
 121         if (clk->flags & AUTOIDLE_LOW)
 122                 val &= ~(1 << clk->shift);
 123         else
 124                 val |= (1 << clk->shift);
 125 
 126         ti_clk_ll_ops->clk_writel(val, &clk->reg);
 127 }
 128 
 129 static void _deny_autoidle(struct clk_ti_autoidle *clk)
 130 {
 131         u32 val;
 132 
 133         val = ti_clk_ll_ops->clk_readl(&clk->reg);
 134 
 135         if (clk->flags & AUTOIDLE_LOW)
 136                 val |= (1 << clk->shift);
 137         else
 138                 val &= ~(1 << clk->shift);
 139 
 140         ti_clk_ll_ops->clk_writel(val, &clk->reg);
 141 }
 142 
 143 /**
 144  * _clk_generic_allow_autoidle_all - enable autoidle for all clocks
 145  *
 146  * Enables hardware autoidle for all registered DT clocks, which have
 147  * the feature.
 148  */
 149 static void _clk_generic_allow_autoidle_all(void)
 150 {
 151         struct clk_ti_autoidle *c;
 152 
 153         list_for_each_entry(c, &autoidle_clks, node)
 154                 _allow_autoidle(c);
 155 }
 156 
 157 /**
 158  * _clk_generic_deny_autoidle_all - disable autoidle for all clocks
 159  *
 160  * Disables hardware autoidle for all registered DT clocks, which have
 161  * the feature.
 162  */
 163 static void _clk_generic_deny_autoidle_all(void)
 164 {
 165         struct clk_ti_autoidle *c;
 166 
 167         list_for_each_entry(c, &autoidle_clks, node)
 168                 _deny_autoidle(c);
 169 }
 170 
 171 /**
 172  * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock
 173  * @node: pointer to the clock device node
 174  *
 175  * Checks if a clock has hardware autoidle support or not (check
 176  * for presence of 'ti,autoidle-shift' property in the device tree
 177  * node) and sets up the hardware autoidle feature for the clock
 178  * if available. If autoidle is available, the clock is also added
 179  * to the autoidle list for later processing. Returns 0 on success,
 180  * negative error value on failure.
 181  */
 182 int __init of_ti_clk_autoidle_setup(struct device_node *node)
 183 {
 184         u32 shift;
 185         struct clk_ti_autoidle *clk;
 186         int ret;
 187 
 188         /* Check if this clock has autoidle support or not */
 189         if (of_property_read_u32(node, "ti,autoidle-shift", &shift))
 190                 return 0;
 191 
 192         clk = kzalloc(sizeof(*clk), GFP_KERNEL);
 193 
 194         if (!clk)
 195                 return -ENOMEM;
 196 
 197         clk->shift = shift;
 198         clk->name = node->name;
 199         ret = ti_clk_get_reg_addr(node, 0, &clk->reg);
 200         if (ret) {
 201                 kfree(clk);
 202                 return ret;
 203         }
 204 
 205         if (of_property_read_bool(node, "ti,invert-autoidle-bit"))
 206                 clk->flags |= AUTOIDLE_LOW;
 207 
 208         list_add(&clk->node, &autoidle_clks);
 209 
 210         return 0;
 211 }
 212 
 213 /**
 214  * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that
 215  * support it
 216  *
 217  * Enable clock autoidle on all OMAP clocks that have allow_idle
 218  * function pointers associated with them.  This function is intended
 219  * to be temporary until support for this is added to the common clock
 220  * code.  Returns 0.
 221  */
 222 int omap2_clk_enable_autoidle_all(void)
 223 {
 224         int ret;
 225 
 226         ret = omap2_clk_for_each(_omap2_clk_allow_idle);
 227         if (ret)
 228                 return ret;
 229 
 230         _clk_generic_allow_autoidle_all();
 231 
 232         return 0;
 233 }
 234 
 235 /**
 236  * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that
 237  * support it
 238  *
 239  * Disable clock autoidle on all OMAP clocks that have allow_idle
 240  * function pointers associated with them.  This function is intended
 241  * to be temporary until support for this is added to the common clock
 242  * code.  Returns 0.
 243  */
 244 int omap2_clk_disable_autoidle_all(void)
 245 {
 246         int ret;
 247 
 248         ret = omap2_clk_for_each(_omap2_clk_deny_idle);
 249         if (ret)
 250                 return ret;
 251 
 252         _clk_generic_deny_autoidle_all();
 253 
 254         return 0;
 255 }

/* [<][>][^][v][top][bottom][index][help] */