Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: keystone: Add gate control clock driver

Add the driver for the clock gate control which uses PSC (Power Sleep
Controller) IP on Keystone 2 based SOCs. It is responsible for enabling and
disabling of the clocks for different IPs present in the SoC.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Santosh Shilimkar and committed by
Mike Turquette
7affe568 b9e0d40c

+293
+29
Documentation/devicetree/bindings/clock/keystone-gate.txt
··· 1 + Status: Unstable - ABI compatibility may be broken in the future 2 + 3 + Binding for Keystone gate control driver which uses PSC controller IP. 4 + 5 + This binding uses the common clock binding[1]. 6 + 7 + [1] Documentation/devicetree/bindings/clock/clock-bindings.txt 8 + 9 + Required properties: 10 + - compatible : shall be "ti,keystone,psc-clock". 11 + - #clock-cells : from common clock binding; shall be set to 0. 12 + - clocks : parent clock phandle 13 + - reg : psc control and domain address address space 14 + - reg-names : psc control and domain registers 15 + - domain-id : psc domain id needed to check the transition state register 16 + 17 + Optional properties: 18 + - clock-output-names : From common clock binding to override the 19 + default output clock name 20 + Example: 21 + clkusb: clkusb { 22 + #clock-cells = <0>; 23 + compatible = "ti,keystone,psc-clock"; 24 + clocks = <&chipclk16>; 25 + clock-output-names = "usb"; 26 + reg = <0x02350008 0xb00>, <0x02350000 0x400>; 27 + reg-names = "control", "domain"; 28 + domain-id = <0>; 29 + };
+264
drivers/clk/keystone/gate.c
··· 1 + /* 2 + * Clock driver for Keystone 2 based devices 3 + * 4 + * Copyright (C) 2013 Texas Instruments. 5 + * Murali Karicheri <m-karicheri2@ti.com> 6 + * Santosh Shilimkar <santosh.shilimkar@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 as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + */ 13 + #include <linux/clk.h> 14 + #include <linux/clk-provider.h> 15 + #include <linux/err.h> 16 + #include <linux/io.h> 17 + #include <linux/slab.h> 18 + #include <linux/of_address.h> 19 + #include <linux/of.h> 20 + #include <linux/module.h> 21 + 22 + /* PSC register offsets */ 23 + #define PTCMD 0x120 24 + #define PTSTAT 0x128 25 + #define PDSTAT 0x200 26 + #define PDCTL 0x300 27 + #define MDSTAT 0x800 28 + #define MDCTL 0xa00 29 + 30 + /* PSC module states */ 31 + #define PSC_STATE_SWRSTDISABLE 0 32 + #define PSC_STATE_SYNCRST 1 33 + #define PSC_STATE_DISABLE 2 34 + #define PSC_STATE_ENABLE 3 35 + 36 + #define MDSTAT_STATE_MASK 0x3f 37 + #define MDSTAT_MCKOUT BIT(12) 38 + #define PDSTAT_STATE_MASK 0x1f 39 + #define MDCTL_FORCE BIT(31) 40 + #define MDCTL_LRESET BIT(8) 41 + #define PDCTL_NEXT BIT(0) 42 + 43 + /* Maximum timeout to bail out state transition for module */ 44 + #define STATE_TRANS_MAX_COUNT 0xffff 45 + 46 + static void __iomem *domain_transition_base; 47 + 48 + /** 49 + * struct clk_psc_data - PSC data 50 + * @control_base: Base address for a PSC control 51 + * @domain_base: Base address for a PSC domain 52 + * @domain_id: PSC domain id number 53 + */ 54 + struct clk_psc_data { 55 + void __iomem *control_base; 56 + void __iomem *domain_base; 57 + u32 domain_id; 58 + }; 59 + 60 + /** 61 + * struct clk_psc - PSC clock structure 62 + * @hw: clk_hw for the psc 63 + * @psc_data: PSC driver specific data 64 + * @lock: Spinlock used by the driver 65 + */ 66 + struct clk_psc { 67 + struct clk_hw hw; 68 + struct clk_psc_data *psc_data; 69 + spinlock_t *lock; 70 + }; 71 + 72 + static DEFINE_SPINLOCK(psc_lock); 73 + 74 + #define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw) 75 + 76 + static void psc_config(void __iomem *control_base, void __iomem *domain_base, 77 + u32 next_state, u32 domain_id) 78 + { 79 + u32 ptcmd, pdstat, pdctl, mdstat, mdctl, ptstat; 80 + u32 count = STATE_TRANS_MAX_COUNT; 81 + 82 + mdctl = readl(control_base + MDCTL); 83 + mdctl &= ~MDSTAT_STATE_MASK; 84 + mdctl |= next_state; 85 + /* For disable, we always put the module in local reset */ 86 + if (next_state == PSC_STATE_DISABLE) 87 + mdctl &= ~MDCTL_LRESET; 88 + writel(mdctl, control_base + MDCTL); 89 + 90 + pdstat = readl(domain_base + PDSTAT); 91 + if (!(pdstat & PDSTAT_STATE_MASK)) { 92 + pdctl = readl(domain_base + PDCTL); 93 + pdctl |= PDCTL_NEXT; 94 + writel(pdctl, domain_base + PDCTL); 95 + } 96 + 97 + ptcmd = 1 << domain_id; 98 + writel(ptcmd, domain_transition_base + PTCMD); 99 + do { 100 + ptstat = readl(domain_transition_base + PTSTAT); 101 + } while (((ptstat >> domain_id) & 1) && count--); 102 + 103 + count = STATE_TRANS_MAX_COUNT; 104 + do { 105 + mdstat = readl(control_base + MDSTAT); 106 + } while (!((mdstat & MDSTAT_STATE_MASK) == next_state) && count--); 107 + } 108 + 109 + static int keystone_clk_is_enabled(struct clk_hw *hw) 110 + { 111 + struct clk_psc *psc = to_clk_psc(hw); 112 + struct clk_psc_data *data = psc->psc_data; 113 + u32 mdstat = readl(data->control_base + MDSTAT); 114 + 115 + return (mdstat & MDSTAT_MCKOUT) ? 1 : 0; 116 + } 117 + 118 + static int keystone_clk_enable(struct clk_hw *hw) 119 + { 120 + struct clk_psc *psc = to_clk_psc(hw); 121 + struct clk_psc_data *data = psc->psc_data; 122 + unsigned long flags = 0; 123 + 124 + if (psc->lock) 125 + spin_lock_irqsave(psc->lock, flags); 126 + 127 + psc_config(data->control_base, data->domain_base, 128 + PSC_STATE_ENABLE, data->domain_id); 129 + 130 + if (psc->lock) 131 + spin_unlock_irqrestore(psc->lock, flags); 132 + 133 + return 0; 134 + } 135 + 136 + static void keystone_clk_disable(struct clk_hw *hw) 137 + { 138 + struct clk_psc *psc = to_clk_psc(hw); 139 + struct clk_psc_data *data = psc->psc_data; 140 + unsigned long flags = 0; 141 + 142 + if (psc->lock) 143 + spin_lock_irqsave(psc->lock, flags); 144 + 145 + psc_config(data->control_base, data->domain_base, 146 + PSC_STATE_DISABLE, data->domain_id); 147 + 148 + if (psc->lock) 149 + spin_unlock_irqrestore(psc->lock, flags); 150 + } 151 + 152 + static const struct clk_ops clk_psc_ops = { 153 + .enable = keystone_clk_enable, 154 + .disable = keystone_clk_disable, 155 + .is_enabled = keystone_clk_is_enabled, 156 + }; 157 + 158 + /** 159 + * clk_register_psc - register psc clock 160 + * @dev: device that is registering this clock 161 + * @name: name of this clock 162 + * @parent_name: name of clock's parent 163 + * @psc_data: platform data to configure this clock 164 + * @lock: spinlock used by this clock 165 + */ 166 + static struct clk *clk_register_psc(struct device *dev, 167 + const char *name, 168 + const char *parent_name, 169 + struct clk_psc_data *psc_data, 170 + spinlock_t *lock) 171 + { 172 + struct clk_init_data init; 173 + struct clk_psc *psc; 174 + struct clk *clk; 175 + 176 + psc = kzalloc(sizeof(*psc), GFP_KERNEL); 177 + if (!psc) 178 + return ERR_PTR(-ENOMEM); 179 + 180 + init.name = name; 181 + init.ops = &clk_psc_ops; 182 + init.parent_names = (parent_name ? &parent_name : NULL); 183 + init.num_parents = (parent_name ? 1 : 0); 184 + 185 + psc->psc_data = psc_data; 186 + psc->lock = lock; 187 + psc->hw.init = &init; 188 + 189 + clk = clk_register(NULL, &psc->hw); 190 + if (IS_ERR(clk)) 191 + kfree(psc); 192 + 193 + return clk; 194 + } 195 + 196 + /** 197 + * of_psc_clk_init - initialize psc clock through DT 198 + * @node: device tree node for this clock 199 + * @lock: spinlock used by this clock 200 + */ 201 + static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock) 202 + { 203 + const char *clk_name = node->name; 204 + const char *parent_name; 205 + struct clk_psc_data *data; 206 + struct clk *clk; 207 + int i; 208 + 209 + data = kzalloc(sizeof(*data), GFP_KERNEL); 210 + if (!data) { 211 + pr_err("%s: Out of memory\n", __func__); 212 + return; 213 + } 214 + 215 + i = of_property_match_string(node, "reg-names", "control"); 216 + data->control_base = of_iomap(node, i); 217 + if (!data->control_base) { 218 + pr_err("%s: control ioremap failed\n", __func__); 219 + goto out; 220 + } 221 + 222 + i = of_property_match_string(node, "reg-names", "domain"); 223 + data->domain_base = of_iomap(node, i); 224 + if (!data->domain_base) { 225 + pr_err("%s: domain ioremap failed\n", __func__); 226 + iounmap(data->control_base); 227 + goto out; 228 + } 229 + 230 + of_property_read_u32(node, "domain-id", &data->domain_id); 231 + 232 + /* Domain transition registers at fixed address space of domain_id 0 */ 233 + if (!domain_transition_base && !data->domain_id) 234 + domain_transition_base = data->domain_base; 235 + 236 + of_property_read_string(node, "clock-output-names", &clk_name); 237 + parent_name = of_clk_get_parent_name(node, 0); 238 + if (!parent_name) { 239 + pr_err("%s: Parent clock not found\n", __func__); 240 + goto out; 241 + } 242 + 243 + clk = clk_register_psc(NULL, clk_name, parent_name, data, lock); 244 + if (clk) { 245 + of_clk_add_provider(node, of_clk_src_simple_get, clk); 246 + return; 247 + } 248 + 249 + pr_err("%s: error registering clk %s\n", __func__, node->name); 250 + out: 251 + kfree(data); 252 + return; 253 + } 254 + 255 + /** 256 + * of_keystone_psc_clk_init - initialize psc clock through DT 257 + * @node: device tree node for this clock 258 + */ 259 + static void __init of_keystone_psc_clk_init(struct device_node *node) 260 + { 261 + of_psc_clk_init(node, &psc_lock); 262 + } 263 + CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock", 264 + of_keystone_psc_clk_init);