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

MXC family: Add clock handling

Internal clock path handling for the mxc CPUs.

Changed against the original Freescale code (and against clocklib for example):
- clock rate is always calculated whenever one ask for the current rate
(means struct clk has no more a member called "rate"). So switching the PLL
base frequency will propagate immediately to all other clocks that are
depending on this frequency.

Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>

authored by

Juergen Beisert and committed by
Robert Schwebel
c0db2ea4 38a41fdf

+399 -1
+1 -1
arch/arm/plat-mxc/Makefile
··· 3 3 # 4 4 5 5 # Common support 6 - obj-y := irq.o 6 + obj-y := irq.o clock.o
+331
arch/arm/plat-mxc/clock.c
··· 1 + /* 2 + * Based on arch/arm/plat-omap/clock.c 3 + * 4 + * Copyright (C) 2004 - 2005 Nokia corporation 5 + * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 6 + * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> 7 + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. 8 + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de 9 + * 10 + * This program is free software; you can redistribute it and/or 11 + * modify it under the terms of the GNU General Public License 12 + * as published by the Free Software Foundation; either version 2 13 + * of the License, or (at your option) any later version. 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program; if not, write to the Free Software 21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 22 + * MA 02110-1301, USA. 23 + */ 24 + 25 + /* #define DEBUG */ 26 + 27 + #include <linux/clk.h> 28 + #include <linux/err.h> 29 + #include <linux/errno.h> 30 + #include <linux/init.h> 31 + #include <linux/io.h> 32 + #include <linux/kernel.h> 33 + #include <linux/list.h> 34 + #include <linux/module.h> 35 + #include <linux/mutex.h> 36 + #include <linux/platform_device.h> 37 + #include <linux/proc_fs.h> 38 + #include <linux/semaphore.h> 39 + #include <linux/string.h> 40 + #include <linux/version.h> 41 + 42 + #include <asm/arch/clock.h> 43 + 44 + static LIST_HEAD(clocks); 45 + static DEFINE_MUTEX(clocks_mutex); 46 + 47 + /*------------------------------------------------------------------------- 48 + * Standard clock functions defined in include/linux/clk.h 49 + *-------------------------------------------------------------------------*/ 50 + 51 + /* 52 + * Retrieve a clock by name. 53 + * 54 + * Note that we first try to use device id on the bus 55 + * and clock name. If this fails, we try to use "<name>.<id>". If this fails, 56 + * we try to use clock name only. 57 + * The reference count to the clock's module owner ref count is incremented. 58 + */ 59 + struct clk *clk_get(struct device *dev, const char *id) 60 + { 61 + struct clk *p, *clk = ERR_PTR(-ENOENT); 62 + int idno; 63 + const char *str; 64 + 65 + if (id == NULL) 66 + return clk; 67 + 68 + if (dev == NULL || dev->bus != &platform_bus_type) 69 + idno = -1; 70 + else 71 + idno = to_platform_device(dev)->id; 72 + 73 + mutex_lock(&clocks_mutex); 74 + 75 + list_for_each_entry(p, &clocks, node) { 76 + if (p->id == idno && 77 + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 78 + clk = p; 79 + goto found; 80 + } 81 + } 82 + 83 + str = strrchr(id, '.'); 84 + if (str) { 85 + int cnt = str - id; 86 + str++; 87 + idno = simple_strtol(str, NULL, 10); 88 + list_for_each_entry(p, &clocks, node) { 89 + if (p->id == idno && 90 + strlen(p->name) == cnt && 91 + strncmp(id, p->name, cnt) == 0 && 92 + try_module_get(p->owner)) { 93 + clk = p; 94 + goto found; 95 + } 96 + } 97 + } 98 + 99 + list_for_each_entry(p, &clocks, node) { 100 + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 101 + clk = p; 102 + goto found; 103 + } 104 + } 105 + 106 + printk(KERN_WARNING "clk: Unable to get requested clock: %s\n", id); 107 + 108 + found: 109 + mutex_unlock(&clocks_mutex); 110 + 111 + return clk; 112 + } 113 + EXPORT_SYMBOL(clk_get); 114 + 115 + static void __clk_disable(struct clk *clk) 116 + { 117 + if (clk == NULL || IS_ERR(clk)) 118 + return; 119 + 120 + __clk_disable(clk->parent); 121 + __clk_disable(clk->secondary); 122 + 123 + if (!(--clk->usecount) && clk->disable) 124 + clk->disable(clk); 125 + } 126 + 127 + static int __clk_enable(struct clk *clk) 128 + { 129 + if (clk == NULL || IS_ERR(clk)) 130 + return -EINVAL; 131 + 132 + __clk_enable(clk->parent); 133 + __clk_enable(clk->secondary); 134 + 135 + if (clk->usecount++ == 0 && clk->enable) 136 + clk->enable(clk); 137 + 138 + return 0; 139 + } 140 + 141 + /* This function increments the reference count on the clock and enables the 142 + * clock if not already enabled. The parent clock tree is recursively enabled 143 + */ 144 + int clk_enable(struct clk *clk) 145 + { 146 + int ret = 0; 147 + 148 + if (clk == NULL || IS_ERR(clk)) 149 + return -EINVAL; 150 + 151 + mutex_lock(&clocks_mutex); 152 + ret = __clk_enable(clk); 153 + mutex_unlock(&clocks_mutex); 154 + 155 + return ret; 156 + } 157 + EXPORT_SYMBOL(clk_enable); 158 + 159 + /* This function decrements the reference count on the clock and disables 160 + * the clock when reference count is 0. The parent clock tree is 161 + * recursively disabled 162 + */ 163 + void clk_disable(struct clk *clk) 164 + { 165 + if (clk == NULL || IS_ERR(clk)) 166 + return; 167 + 168 + mutex_lock(&clocks_mutex); 169 + __clk_disable(clk); 170 + mutex_unlock(&clocks_mutex); 171 + } 172 + EXPORT_SYMBOL(clk_disable); 173 + 174 + /* Retrieve the *current* clock rate. If the clock itself 175 + * does not provide a special calculation routine, ask 176 + * its parent and so on, until one is able to return 177 + * a valid clock rate 178 + */ 179 + unsigned long clk_get_rate(struct clk *clk) 180 + { 181 + if (clk == NULL || IS_ERR(clk)) 182 + return 0UL; 183 + 184 + if (clk->get_rate) 185 + return clk->get_rate(clk); 186 + 187 + return clk_get_rate(clk->parent); 188 + } 189 + EXPORT_SYMBOL(clk_get_rate); 190 + 191 + /* Decrement the clock's module reference count */ 192 + void clk_put(struct clk *clk) 193 + { 194 + if (clk && !IS_ERR(clk)) 195 + module_put(clk->owner); 196 + } 197 + EXPORT_SYMBOL(clk_put); 198 + 199 + /* Round the requested clock rate to the nearest supported 200 + * rate that is less than or equal to the requested rate. 201 + * This is dependent on the clock's current parent. 202 + */ 203 + long clk_round_rate(struct clk *clk, unsigned long rate) 204 + { 205 + if (clk == NULL || IS_ERR(clk) || !clk->round_rate) 206 + return 0; 207 + 208 + return clk->round_rate(clk, rate); 209 + } 210 + EXPORT_SYMBOL(clk_round_rate); 211 + 212 + /* Set the clock to the requested clock rate. The rate must 213 + * match a supported rate exactly based on what clk_round_rate returns 214 + */ 215 + int clk_set_rate(struct clk *clk, unsigned long rate) 216 + { 217 + int ret = -EINVAL; 218 + 219 + if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) 220 + return ret; 221 + 222 + mutex_lock(&clocks_mutex); 223 + ret = clk->set_rate(clk, rate); 224 + mutex_unlock(&clocks_mutex); 225 + 226 + return ret; 227 + } 228 + EXPORT_SYMBOL(clk_set_rate); 229 + 230 + /* Set the clock's parent to another clock source */ 231 + int clk_set_parent(struct clk *clk, struct clk *parent) 232 + { 233 + int ret = -EINVAL; 234 + 235 + if (clk == NULL || IS_ERR(clk) || parent == NULL || 236 + IS_ERR(parent) || clk->set_parent == NULL) 237 + return ret; 238 + 239 + mutex_lock(&clocks_mutex); 240 + ret = clk->set_parent(clk, parent); 241 + if (ret == 0) 242 + clk->parent = parent; 243 + mutex_unlock(&clocks_mutex); 244 + 245 + return ret; 246 + } 247 + EXPORT_SYMBOL(clk_set_parent); 248 + 249 + /* Retrieve the clock's parent clock source */ 250 + struct clk *clk_get_parent(struct clk *clk) 251 + { 252 + struct clk *ret = NULL; 253 + 254 + if (clk == NULL || IS_ERR(clk)) 255 + return ret; 256 + 257 + return clk->parent; 258 + } 259 + EXPORT_SYMBOL(clk_get_parent); 260 + 261 + /* 262 + * Add a new clock to the clock tree. 263 + */ 264 + int clk_register(struct clk *clk) 265 + { 266 + if (clk == NULL || IS_ERR(clk)) 267 + return -EINVAL; 268 + 269 + mutex_lock(&clocks_mutex); 270 + list_add(&clk->node, &clocks); 271 + mutex_unlock(&clocks_mutex); 272 + 273 + return 0; 274 + } 275 + EXPORT_SYMBOL(clk_register); 276 + 277 + /* Remove a clock from the clock tree */ 278 + void clk_unregister(struct clk *clk) 279 + { 280 + if (clk == NULL || IS_ERR(clk)) 281 + return; 282 + 283 + mutex_lock(&clocks_mutex); 284 + list_del(&clk->node); 285 + mutex_unlock(&clocks_mutex); 286 + } 287 + EXPORT_SYMBOL(clk_unregister); 288 + 289 + #ifdef CONFIG_PROC_FS 290 + static int mxc_clock_read_proc(char *page, char **start, off_t off, 291 + int count, int *eof, void *data) 292 + { 293 + struct clk *clkp; 294 + char *p = page; 295 + int len; 296 + 297 + list_for_each_entry(clkp, &clocks, node) { 298 + p += sprintf(p, "%s-%d:\t\t%lu, %d", clkp->name, clkp->id, 299 + clk_get_rate(clkp), clkp->usecount); 300 + if (clkp->parent) 301 + p += sprintf(p, ", %s-%d\n", clkp->parent->name, 302 + clkp->parent->id); 303 + else 304 + p += sprintf(p, "\n"); 305 + } 306 + 307 + len = (p - page) - off; 308 + if (len < 0) 309 + len = 0; 310 + 311 + *eof = (len <= count) ? 1 : 0; 312 + *start = page + off; 313 + 314 + return len; 315 + } 316 + 317 + static int __init mxc_setup_proc_entry(void) 318 + { 319 + struct proc_dir_entry *res; 320 + 321 + res = create_proc_read_entry("cpu/clocks", 0, NULL, 322 + mxc_clock_read_proc, NULL); 323 + if (!res) { 324 + printk(KERN_ERR "Failed to create proc/cpu/clocks\n"); 325 + return -ENOMEM; 326 + } 327 + return 0; 328 + } 329 + 330 + late_initcall(mxc_setup_proc_entry); 331 + #endif
+67
include/asm-arm/arch-mxc/clock.h
··· 1 + /* 2 + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. 3 + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation; either version 2 8 + * of the License, or (at your option) any later version. 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 + * MA 02110-1301, USA. 18 + */ 19 + 20 + #ifndef __ASM_ARCH_MXC_CLOCK_H__ 21 + #define __ASM_ARCH_MXC_CLOCK_H__ 22 + 23 + #ifndef __ASSEMBLY__ 24 + #include <linux/list.h> 25 + 26 + struct module; 27 + 28 + struct clk { 29 + struct list_head node; 30 + struct module *owner; 31 + const char *name; 32 + int id; 33 + /* Source clock this clk depends on */ 34 + struct clk *parent; 35 + /* Secondary clock to enable/disable with this clock */ 36 + struct clk *secondary; 37 + /* Reference count of clock enable/disable */ 38 + __s8 usecount; 39 + /* Register bit position for clock's enable/disable control. */ 40 + u8 enable_shift; 41 + /* Register address for clock's enable/disable control. */ 42 + u32 enable_reg; 43 + u32 flags; 44 + /* get the current clock rate (always a fresh value) */ 45 + unsigned long (*get_rate) (struct clk *); 46 + /* Function ptr to set the clock to a new rate. The rate must match a 47 + supported rate returned from round_rate. Leave blank if clock is not 48 + programmable */ 49 + int (*set_rate) (struct clk *, unsigned long); 50 + /* Function ptr to round the requested clock rate to the nearest 51 + supported rate that is less than or equal to the requested rate. */ 52 + unsigned long (*round_rate) (struct clk *, unsigned long); 53 + /* Function ptr to enable the clock. Leave blank if clock can not 54 + be gated. */ 55 + int (*enable) (struct clk *); 56 + /* Function ptr to disable the clock. Leave blank if clock can not 57 + be gated. */ 58 + void (*disable) (struct clk *); 59 + /* Function ptr to set the parent clock of the clock. */ 60 + int (*set_parent) (struct clk *, struct clk *); 61 + }; 62 + 63 + int clk_register(struct clk *clk); 64 + void clk_unregister(struct clk *clk); 65 + 66 + #endif /* __ASSEMBLY__ */ 67 + #endif /* __ASM_ARCH_MXC_CLOCK_H__ */