1/* 2 * R-Car MSTP clocks 3 * 4 * Copyright (C) 2013 Ideas On Board SPRL 5 * 6 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License. 11 */ 12 13#include <linux/clk-provider.h> 14#include <linux/clkdev.h> 15#include <linux/io.h> 16#include <linux/of.h> 17#include <linux/of_address.h> 18#include <linux/spinlock.h> 19 20/* 21 * MSTP clocks. We can't use standard gate clocks as we need to poll on the 22 * status register when enabling the clock. 23 */ 24 25#define MSTP_MAX_CLOCKS 32 26 27/** 28 * struct mstp_clock_group - MSTP gating clocks group 29 * 30 * @data: clocks in this group 31 * @smstpcr: module stop control register 32 * @mstpsr: module stop status register (optional) 33 * @lock: protects writes to SMSTPCR 34 */ 35struct mstp_clock_group { 36 struct clk_onecell_data data; 37 void __iomem *smstpcr; 38 void __iomem *mstpsr; 39 spinlock_t lock; 40}; 41 42/** 43 * struct mstp_clock - MSTP gating clock 44 * @hw: handle between common and hardware-specific interfaces 45 * @bit_index: control bit index 46 * @group: MSTP clocks group 47 */ 48struct mstp_clock { 49 struct clk_hw hw; 50 u32 bit_index; 51 struct mstp_clock_group *group; 52}; 53 54#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) 55 56static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) 57{ 58 struct mstp_clock *clock = to_mstp_clock(hw); 59 struct mstp_clock_group *group = clock->group; 60 u32 bitmask = BIT(clock->bit_index); 61 unsigned long flags; 62 unsigned int i; 63 u32 value; 64 65 spin_lock_irqsave(&group->lock, flags); 66 67 value = clk_readl(group->smstpcr); 68 if (enable) 69 value &= ~bitmask; 70 else 71 value |= bitmask; 72 clk_writel(value, group->smstpcr); 73 74 spin_unlock_irqrestore(&group->lock, flags); 75 76 if (!enable || !group->mstpsr) 77 return 0; 78 79 for (i = 1000; i > 0; --i) { 80 if (!(clk_readl(group->mstpsr) & bitmask)) 81 break; 82 cpu_relax(); 83 } 84 85 if (!i) { 86 pr_err("%s: failed to enable %p[%d]\n", __func__, 87 group->smstpcr, clock->bit_index); 88 return -ETIMEDOUT; 89 } 90 91 return 0; 92} 93 94static int cpg_mstp_clock_enable(struct clk_hw *hw) 95{ 96 return cpg_mstp_clock_endisable(hw, true); 97} 98 99static void cpg_mstp_clock_disable(struct clk_hw *hw) 100{ 101 cpg_mstp_clock_endisable(hw, false); 102} 103 104static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) 105{ 106 struct mstp_clock *clock = to_mstp_clock(hw); 107 struct mstp_clock_group *group = clock->group; 108 u32 value; 109 110 if (group->mstpsr) 111 value = clk_readl(group->mstpsr); 112 else 113 value = clk_readl(group->smstpcr); 114 115 return !(value & BIT(clock->bit_index)); 116} 117 118static const struct clk_ops cpg_mstp_clock_ops = { 119 .enable = cpg_mstp_clock_enable, 120 .disable = cpg_mstp_clock_disable, 121 .is_enabled = cpg_mstp_clock_is_enabled, 122}; 123 124static struct clk * __init 125cpg_mstp_clock_register(const char *name, const char *parent_name, 126 unsigned int index, struct mstp_clock_group *group) 127{ 128 struct clk_init_data init; 129 struct mstp_clock *clock; 130 struct clk *clk; 131 132 clock = kzalloc(sizeof(*clock), GFP_KERNEL); 133 if (!clock) { 134 pr_err("%s: failed to allocate MSTP clock.\n", __func__); 135 return ERR_PTR(-ENOMEM); 136 } 137 138 init.name = name; 139 init.ops = &cpg_mstp_clock_ops; 140 init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; 141 init.parent_names = &parent_name; 142 init.num_parents = 1; 143 144 clock->bit_index = index; 145 clock->group = group; 146 clock->hw.init = &init; 147 148 clk = clk_register(NULL, &clock->hw); 149 150 if (IS_ERR(clk)) 151 kfree(clock); 152 153 return clk; 154} 155 156static void __init cpg_mstp_clocks_init(struct device_node *np) 157{ 158 struct mstp_clock_group *group; 159 const char *idxname; 160 struct clk **clks; 161 unsigned int i; 162 163 group = kzalloc(sizeof(*group), GFP_KERNEL); 164 clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL); 165 if (group == NULL || clks == NULL) { 166 kfree(group); 167 kfree(clks); 168 pr_err("%s: failed to allocate group\n", __func__); 169 return; 170 } 171 172 spin_lock_init(&group->lock); 173 group->data.clks = clks; 174 175 group->smstpcr = of_iomap(np, 0); 176 group->mstpsr = of_iomap(np, 1); 177 178 if (group->smstpcr == NULL) { 179 pr_err("%s: failed to remap SMSTPCR\n", __func__); 180 kfree(group); 181 kfree(clks); 182 return; 183 } 184 185 for (i = 0; i < MSTP_MAX_CLOCKS; ++i) 186 clks[i] = ERR_PTR(-ENOENT); 187 188 if (of_find_property(np, "clock-indices", &i)) 189 idxname = "clock-indices"; 190 else 191 idxname = "renesas,clock-indices"; 192 193 for (i = 0; i < MSTP_MAX_CLOCKS; ++i) { 194 const char *parent_name; 195 const char *name; 196 u32 clkidx; 197 int ret; 198 199 /* Skip clocks with no name. */ 200 ret = of_property_read_string_index(np, "clock-output-names", 201 i, &name); 202 if (ret < 0 || strlen(name) == 0) 203 continue; 204 205 parent_name = of_clk_get_parent_name(np, i); 206 ret = of_property_read_u32_index(np, idxname, i, &clkidx); 207 if (parent_name == NULL || ret < 0) 208 break; 209 210 if (clkidx >= MSTP_MAX_CLOCKS) { 211 pr_err("%s: invalid clock %s %s index %u)\n", 212 __func__, np->name, name, clkidx); 213 continue; 214 } 215 216 clks[clkidx] = cpg_mstp_clock_register(name, parent_name, 217 clkidx, group); 218 if (!IS_ERR(clks[clkidx])) { 219 group->data.clk_num = max(group->data.clk_num, 220 clkidx + 1); 221 /* 222 * Register a clkdev to let board code retrieve the 223 * clock by name and register aliases for non-DT 224 * devices. 225 * 226 * FIXME: Remove this when all devices that require a 227 * clock will be instantiated from DT. 228 */ 229 clk_register_clkdev(clks[clkidx], name, NULL); 230 } else { 231 pr_err("%s: failed to register %s %s clock (%ld)\n", 232 __func__, np->name, name, PTR_ERR(clks[clkidx])); 233 } 234 } 235 236 of_clk_add_provider(np, of_clk_src_onecell_get, &group->data); 237} 238CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); 239