linux/drivers/clk/ti/gate.c
<<
>>
Prefs
   1/*
   2 * OMAP gate clock 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#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
  28
  29#undef pr_fmt
  30#define pr_fmt(fmt) "%s: " fmt, __func__
  31
  32static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk);
  33
  34static const struct clk_ops omap_gate_clkdm_clk_ops = {
  35        .init           = &omap2_init_clk_clkdm,
  36        .enable         = &omap2_clkops_enable_clkdm,
  37        .disable        = &omap2_clkops_disable_clkdm,
  38};
  39
  40static const struct clk_ops omap_gate_clk_ops = {
  41        .init           = &omap2_init_clk_clkdm,
  42        .enable         = &omap2_dflt_clk_enable,
  43        .disable        = &omap2_dflt_clk_disable,
  44        .is_enabled     = &omap2_dflt_clk_is_enabled,
  45};
  46
  47static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
  48        .init           = &omap2_init_clk_clkdm,
  49        .enable         = &omap36xx_gate_clk_enable_with_hsdiv_restore,
  50        .disable        = &omap2_dflt_clk_disable,
  51        .is_enabled     = &omap2_dflt_clk_is_enabled,
  52};
  53
  54/**
  55 * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering
  56 *         from HSDivider PWRDN problem Implements Errata ID: i556.
  57 * @clk: DPLL output struct clk
  58 *
  59 * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
  60 * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
  61 * valueafter their respective PWRDN bits are set.  Any dummy write
  62 * (Any other value different from the Read value) to the
  63 * corresponding CM_CLKSEL register will refresh the dividers.
  64 */
  65static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *hw)
  66{
  67        struct clk_divider *parent;
  68        struct clk_hw *parent_hw;
  69        u32 dummy_v, orig_v;
  70        int ret;
  71
  72        /* Clear PWRDN bit of HSDIVIDER */
  73        ret = omap2_dflt_clk_enable(hw);
  74
  75        /* Parent is the x2 node, get parent of parent for the m2 div */
  76        parent_hw = clk_hw_get_parent(clk_hw_get_parent(hw));
  77        parent = to_clk_divider(parent_hw);
  78
  79        /* Restore the dividers */
  80        if (!ret) {
  81                orig_v = ti_clk_ll_ops->clk_readl(parent->reg);
  82                dummy_v = orig_v;
  83
  84                /* Write any other value different from the Read value */
  85                dummy_v ^= (1 << parent->shift);
  86                ti_clk_ll_ops->clk_writel(dummy_v, parent->reg);
  87
  88                /* Write the original divider */
  89                ti_clk_ll_ops->clk_writel(orig_v, parent->reg);
  90        }
  91
  92        return ret;
  93}
  94
  95static struct clk *_register_gate(struct device *dev, const char *name,
  96                                  const char *parent_name, unsigned long flags,
  97                                  void __iomem *reg, u8 bit_idx,
  98                                  u8 clk_gate_flags, const struct clk_ops *ops,
  99                                  const struct clk_hw_omap_ops *hw_ops)
 100{
 101        struct clk_init_data init = { NULL };
 102        struct clk_hw_omap *clk_hw;
 103        struct clk *clk;
 104
 105        clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
 106        if (!clk_hw)
 107                return ERR_PTR(-ENOMEM);
 108
 109        clk_hw->hw.init = &init;
 110
 111        init.name = name;
 112        init.ops = ops;
 113
 114        clk_hw->enable_reg = reg;
 115        clk_hw->enable_bit = bit_idx;
 116        clk_hw->ops = hw_ops;
 117
 118        clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags;
 119
 120        init.parent_names = &parent_name;
 121        init.num_parents = 1;
 122
 123        init.flags = flags;
 124
 125        clk = clk_register(NULL, &clk_hw->hw);
 126
 127        if (IS_ERR(clk))
 128                kfree(clk_hw);
 129
 130        return clk;
 131}
 132
 133#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
 134struct clk *ti_clk_register_gate(struct ti_clk *setup)
 135{
 136        const struct clk_ops *ops = &omap_gate_clk_ops;
 137        const struct clk_hw_omap_ops *hw_ops = NULL;
 138        u32 reg;
 139        struct clk_omap_reg *reg_setup;
 140        u32 flags = 0;
 141        u8 clk_gate_flags = 0;
 142        struct ti_clk_gate *gate;
 143
 144        gate = setup->data;
 145
 146        if (gate->flags & CLKF_INTERFACE)
 147                return ti_clk_register_interface(setup);
 148
 149        reg_setup = (struct clk_omap_reg *)&reg;
 150
 151        if (gate->flags & CLKF_SET_RATE_PARENT)
 152                flags |= CLK_SET_RATE_PARENT;
 153
 154        if (gate->flags & CLKF_SET_BIT_TO_DISABLE)
 155                clk_gate_flags |= INVERT_ENABLE;
 156
 157        if (gate->flags & CLKF_HSDIV) {
 158                ops = &omap_gate_clk_hsdiv_restore_ops;
 159                hw_ops = &clkhwops_wait;
 160        }
 161
 162        if (gate->flags & CLKF_DSS)
 163                hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait;
 164
 165        if (gate->flags & CLKF_WAIT)
 166                hw_ops = &clkhwops_wait;
 167
 168        if (gate->flags & CLKF_CLKDM)
 169                ops = &omap_gate_clkdm_clk_ops;
 170
 171        if (gate->flags & CLKF_AM35XX)
 172                hw_ops = &clkhwops_am35xx_ipss_module_wait;
 173
 174        reg_setup->index = gate->module;
 175        reg_setup->offset = gate->reg;
 176
 177        return _register_gate(NULL, setup->name, gate->parent, flags,
 178                              (void __iomem *)reg, gate->bit_shift,
 179                              clk_gate_flags, ops, hw_ops);
 180}
 181
 182struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
 183{
 184        struct clk_hw_omap *gate;
 185        struct clk_omap_reg *reg;
 186        const struct clk_hw_omap_ops *ops = &clkhwops_wait;
 187
 188        if (!setup)
 189                return NULL;
 190
 191        gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 192        if (!gate)
 193                return ERR_PTR(-ENOMEM);
 194
 195        reg = (struct clk_omap_reg *)&gate->enable_reg;
 196        reg->index = setup->module;
 197        reg->offset = setup->reg;
 198
 199        gate->enable_bit = setup->bit_shift;
 200
 201        if (setup->flags & CLKF_NO_WAIT)
 202                ops = NULL;
 203
 204        if (setup->flags & CLKF_INTERFACE)
 205                ops = &clkhwops_iclk_wait;
 206
 207        gate->ops = ops;
 208        gate->flags = MEMMAP_ADDRESSING;
 209
 210        return &gate->hw;
 211}
 212#endif
 213
 214static void __init _of_ti_gate_clk_setup(struct device_node *node,
 215                                         const struct clk_ops *ops,
 216                                         const struct clk_hw_omap_ops *hw_ops)
 217{
 218        struct clk *clk;
 219        const char *parent_name;
 220        void __iomem *reg = NULL;
 221        u8 enable_bit = 0;
 222        u32 val;
 223        u32 flags = 0;
 224        u8 clk_gate_flags = 0;
 225
 226        if (ops != &omap_gate_clkdm_clk_ops) {
 227                reg = ti_clk_get_reg_addr(node, 0);
 228                if (IS_ERR(reg))
 229                        return;
 230
 231                if (!of_property_read_u32(node, "ti,bit-shift", &val))
 232                        enable_bit = val;
 233        }
 234
 235        if (of_clk_get_parent_count(node) != 1) {
 236                pr_err("%s must have 1 parent\n", node->name);
 237                return;
 238        }
 239
 240        parent_name = of_clk_get_parent_name(node, 0);
 241
 242        if (of_property_read_bool(node, "ti,set-rate-parent"))
 243                flags |= CLK_SET_RATE_PARENT;
 244
 245        if (of_property_read_bool(node, "ti,set-bit-to-disable"))
 246                clk_gate_flags |= INVERT_ENABLE;
 247
 248        clk = _register_gate(NULL, node->name, parent_name, flags, reg,
 249                             enable_bit, clk_gate_flags, ops, hw_ops);
 250
 251        if (!IS_ERR(clk))
 252                of_clk_add_provider(node, of_clk_src_simple_get, clk);
 253}
 254
 255static void __init
 256_of_ti_composite_gate_clk_setup(struct device_node *node,
 257                                const struct clk_hw_omap_ops *hw_ops)
 258{
 259        struct clk_hw_omap *gate;
 260        u32 val = 0;
 261
 262        gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 263        if (!gate)
 264                return;
 265
 266        gate->enable_reg = ti_clk_get_reg_addr(node, 0);
 267        if (IS_ERR(gate->enable_reg))
 268                goto cleanup;
 269
 270        of_property_read_u32(node, "ti,bit-shift", &val);
 271
 272        gate->enable_bit = val;
 273        gate->ops = hw_ops;
 274        gate->flags = MEMMAP_ADDRESSING;
 275
 276        if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
 277                return;
 278
 279cleanup:
 280        kfree(gate);
 281}
 282
 283static void __init
 284of_ti_composite_no_wait_gate_clk_setup(struct device_node *node)
 285{
 286        _of_ti_composite_gate_clk_setup(node, NULL);
 287}
 288CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock",
 289               of_ti_composite_no_wait_gate_clk_setup);
 290
 291#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 292static void __init of_ti_composite_interface_clk_setup(struct device_node *node)
 293{
 294        _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait);
 295}
 296CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock",
 297               of_ti_composite_interface_clk_setup);
 298#endif
 299
 300static void __init of_ti_composite_gate_clk_setup(struct device_node *node)
 301{
 302        _of_ti_composite_gate_clk_setup(node, &clkhwops_wait);
 303}
 304CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock",
 305               of_ti_composite_gate_clk_setup);
 306
 307
 308static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node)
 309{
 310        _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL);
 311}
 312CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock",
 313               of_ti_clkdm_gate_clk_setup);
 314
 315static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node)
 316{
 317        _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops,
 318                              &clkhwops_wait);
 319}
 320CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock",
 321               of_ti_hsdiv_gate_clk_setup);
 322
 323static void __init of_ti_gate_clk_setup(struct device_node *node)
 324{
 325        _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
 326}
 327CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
 328
 329static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
 330{
 331        _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait);
 332}
 333CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock",
 334               of_ti_wait_gate_clk_setup);
 335
 336#ifdef CONFIG_ARCH_OMAP3
 337static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node)
 338{
 339        _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
 340                              &clkhwops_am35xx_ipss_module_wait);
 341}
 342CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock",
 343               of_ti_am35xx_gate_clk_setup);
 344
 345static void __init of_ti_dss_gate_clk_setup(struct device_node *node)
 346{
 347        _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
 348                              &clkhwops_omap3430es2_dss_usbhost_wait);
 349}
 350CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock",
 351               of_ti_dss_gate_clk_setup);
 352#endif
 353