ti_prcm.c revision 239281
1239281Sgonzo/* 2239281Sgonzo * Copyright (c) 2010 3239281Sgonzo * Ben Gray <ben.r.gray@gmail.com>. 4239281Sgonzo * All rights reserved. 5239281Sgonzo * 6239281Sgonzo * Redistribution and use in source and binary forms, with or without 7239281Sgonzo * modification, are permitted provided that the following conditions 8239281Sgonzo * are met: 9239281Sgonzo * 1. Redistributions of source code must retain the above copyright 10239281Sgonzo * notice, this list of conditions and the following disclaimer. 11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12239281Sgonzo * notice, this list of conditions and the following disclaimer in the 13239281Sgonzo * documentation and/or other materials provided with the distribution. 14239281Sgonzo * 3. All advertising materials mentioning features or use of this software 15239281Sgonzo * must display the following acknowledgement: 16239281Sgonzo * This product includes software developed by Ben Gray. 17239281Sgonzo * 4. The name of the company nor the name of the author may be used to 18239281Sgonzo * endorse or promote products derived from this software without specific 19239281Sgonzo * prior written permission. 20239281Sgonzo * 21239281Sgonzo * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR 22239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24239281Sgonzo * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25239281Sgonzo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26239281Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27239281Sgonzo * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28239281Sgonzo * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29239281Sgonzo * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30239281Sgonzo * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31239281Sgonzo */ 32239281Sgonzo 33239281Sgonzo/** 34239281Sgonzo * Power, Reset and Clock Managment Module 35239281Sgonzo * 36239281Sgonzo * This is a very simple driver wrapper around the PRCM set of registers in 37239281Sgonzo * the OMAP3 chip. It allows you to turn on and off things like the functional 38239281Sgonzo * and interface clocks to the various on-chip modules. 39239281Sgonzo * 40239281Sgonzo */ 41239281Sgonzo#include <sys/cdefs.h> 42239281Sgonzo__FBSDID("$FreeBSD: head/sys/arm/ti/ti_prcm.c 239281 2012-08-15 06:31:32Z gonzo $"); 43239281Sgonzo 44239281Sgonzo#include <sys/param.h> 45239281Sgonzo#include <sys/systm.h> 46239281Sgonzo#include <sys/kernel.h> 47239281Sgonzo#include <sys/module.h> 48239281Sgonzo#include <sys/bus.h> 49239281Sgonzo#include <sys/resource.h> 50239281Sgonzo#include <sys/rman.h> 51239281Sgonzo#include <sys/lock.h> 52239281Sgonzo#include <sys/mutex.h> 53239281Sgonzo 54239281Sgonzo#include <machine/bus.h> 55239281Sgonzo#include <machine/cpu.h> 56239281Sgonzo#include <machine/cpufunc.h> 57239281Sgonzo#include <machine/frame.h> 58239281Sgonzo#include <machine/resource.h> 59239281Sgonzo#include <machine/intr.h> 60239281Sgonzo 61239281Sgonzo#include <arm/ti/ti_prcm.h> 62239281Sgonzo 63239281Sgonzo/** 64239281Sgonzo * ti_clk_devmap - Array of clock devices, should be defined one per SoC 65239281Sgonzo * 66239281Sgonzo * This array is typically defined in one of the targeted *_prcm_clk.c 67239281Sgonzo * files and is specific to the given SoC platform. Each entry in the array 68239281Sgonzo * corresponds to an individual clock device. 69239281Sgonzo */ 70239281Sgonzoextern struct ti_clock_dev ti_clk_devmap[]; 71239281Sgonzo 72239281Sgonzo/** 73239281Sgonzo * ti_prcm_clk_dev - returns a pointer to the clock device with given id 74239281Sgonzo * @clk: the ID of the clock device to get 75239281Sgonzo * 76239281Sgonzo * Simply iterates through the clk_devmap global array and returns a pointer 77239281Sgonzo * to the clock device if found. 78239281Sgonzo * 79239281Sgonzo * LOCKING: 80239281Sgonzo * None 81239281Sgonzo * 82239281Sgonzo * RETURNS: 83239281Sgonzo * The pointer to the clock device on success, on failure NULL is returned. 84239281Sgonzo */ 85239281Sgonzostatic struct ti_clock_dev * 86239281Sgonzoti_prcm_clk_dev(clk_ident_t clk) 87239281Sgonzo{ 88239281Sgonzo struct ti_clock_dev *clk_dev; 89239281Sgonzo 90239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 91239281Sgonzo * loop for this, but this function should only called when a driver is 92239281Sgonzo * being activated so IMHO not a big issue. 93239281Sgonzo */ 94239281Sgonzo clk_dev = &(ti_clk_devmap[0]); 95239281Sgonzo while (clk_dev->id != INVALID_CLK_IDENT) { 96239281Sgonzo if (clk_dev->id == clk) { 97239281Sgonzo return (clk_dev); 98239281Sgonzo } 99239281Sgonzo clk_dev++; 100239281Sgonzo } 101239281Sgonzo 102239281Sgonzo /* Sanity check we managed to find the clock */ 103239281Sgonzo printf("ti_prcm: Failed to find clock device (%d)\n", clk); 104239281Sgonzo return (NULL); 105239281Sgonzo} 106239281Sgonzo 107239281Sgonzo/** 108239281Sgonzo * ti_prcm_clk_valid - enables a clock for a particular module 109239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 110239281Sgonzo * of possible modules. 111239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 112239281Sgonzo * 113239281Sgonzo * This function can enable either a functional or interface clock. 114239281Sgonzo * 115239281Sgonzo * The real work done to enable the clock is really done in the callback 116239281Sgonzo * function associated with the clock, this function is simply a wrapper 117239281Sgonzo * around that. 118239281Sgonzo * 119239281Sgonzo * LOCKING: 120239281Sgonzo * Internally locks the driver context. 121239281Sgonzo * 122239281Sgonzo * RETURNS: 123239281Sgonzo * Returns 0 on success or positive error code on failure. 124239281Sgonzo */ 125239281Sgonzoint 126239281Sgonzoti_prcm_clk_valid(clk_ident_t clk) 127239281Sgonzo{ 128239281Sgonzo int ret = 0; 129239281Sgonzo 130239281Sgonzo if (ti_prcm_clk_dev(clk) == NULL) 131239281Sgonzo ret = EINVAL; 132239281Sgonzo 133239281Sgonzo return (ret); 134239281Sgonzo} 135239281Sgonzo 136239281Sgonzo 137239281Sgonzo/** 138239281Sgonzo * ti_prcm_clk_enable - enables a clock for a particular module 139239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 140239281Sgonzo * of possible modules. 141239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 142239281Sgonzo * 143239281Sgonzo * This function can enable either a functional or interface clock. 144239281Sgonzo * 145239281Sgonzo * The real work done to enable the clock is really done in the callback 146239281Sgonzo * function associated with the clock, this function is simply a wrapper 147239281Sgonzo * around that. 148239281Sgonzo * 149239281Sgonzo * LOCKING: 150239281Sgonzo * Internally locks the driver context. 151239281Sgonzo * 152239281Sgonzo * RETURNS: 153239281Sgonzo * Returns 0 on success or positive error code on failure. 154239281Sgonzo */ 155239281Sgonzoint 156239281Sgonzoti_prcm_clk_enable(clk_ident_t clk) 157239281Sgonzo{ 158239281Sgonzo struct ti_clock_dev *clk_dev; 159239281Sgonzo int ret; 160239281Sgonzo 161239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 162239281Sgonzo * loop for this, but this function should only called when a driver is 163239281Sgonzo * being activated so IMHO not a big issue. 164239281Sgonzo */ 165239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 166239281Sgonzo 167239281Sgonzo /* Sanity check we managed to find the clock */ 168239281Sgonzo if (clk_dev == NULL) 169239281Sgonzo return (EINVAL); 170239281Sgonzo 171239281Sgonzo /* Activate the clock */ 172239281Sgonzo if (clk_dev->clk_activate) 173239281Sgonzo ret = clk_dev->clk_activate(clk_dev); 174239281Sgonzo else 175239281Sgonzo ret = EINVAL; 176239281Sgonzo 177239281Sgonzo return (ret); 178239281Sgonzo} 179239281Sgonzo 180239281Sgonzo 181239281Sgonzo/** 182239281Sgonzo * ti_prcm_clk_disable - disables a clock for a particular module 183239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 184239281Sgonzo * of possible modules. 185239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 186239281Sgonzo * 187239281Sgonzo * This function can enable either a functional or interface clock. 188239281Sgonzo * 189239281Sgonzo * The real work done to enable the clock is really done in the callback 190239281Sgonzo * function associated with the clock, this function is simply a wrapper 191239281Sgonzo * around that. 192239281Sgonzo * 193239281Sgonzo * LOCKING: 194239281Sgonzo * Internally locks the driver context. 195239281Sgonzo * 196239281Sgonzo * RETURNS: 197239281Sgonzo * Returns 0 on success or positive error code on failure. 198239281Sgonzo */ 199239281Sgonzoint 200239281Sgonzoti_prcm_clk_disable(clk_ident_t clk) 201239281Sgonzo{ 202239281Sgonzo struct ti_clock_dev *clk_dev; 203239281Sgonzo int ret; 204239281Sgonzo 205239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 206239281Sgonzo * loop for this, but this function should only called when a driver is 207239281Sgonzo * being activated so IMHO not a big issue. 208239281Sgonzo */ 209239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 210239281Sgonzo 211239281Sgonzo /* Sanity check we managed to find the clock */ 212239281Sgonzo if (clk_dev == NULL) 213239281Sgonzo return (EINVAL); 214239281Sgonzo 215239281Sgonzo /* Activate the clock */ 216239281Sgonzo if (clk_dev->clk_deactivate) 217239281Sgonzo ret = clk_dev->clk_deactivate(clk_dev); 218239281Sgonzo else 219239281Sgonzo ret = EINVAL; 220239281Sgonzo 221239281Sgonzo return (ret); 222239281Sgonzo} 223239281Sgonzo 224239281Sgonzo/** 225239281Sgonzo * ti_prcm_clk_set_source - sets the source 226239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 227239281Sgonzo * of possible modules. 228239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 229239281Sgonzo * 230239281Sgonzo * This function can enable either a functional or interface clock. 231239281Sgonzo * 232239281Sgonzo * The real work done to enable the clock is really done in the callback 233239281Sgonzo * function associated with the clock, this function is simply a wrapper 234239281Sgonzo * around that. 235239281Sgonzo * 236239281Sgonzo * LOCKING: 237239281Sgonzo * Internally locks the driver context. 238239281Sgonzo * 239239281Sgonzo * RETURNS: 240239281Sgonzo * Returns 0 on success or positive error code on failure. 241239281Sgonzo */ 242239281Sgonzoint 243239281Sgonzoti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc) 244239281Sgonzo{ 245239281Sgonzo struct ti_clock_dev *clk_dev; 246239281Sgonzo int ret; 247239281Sgonzo 248239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 249239281Sgonzo * loop for this, but this function should only called when a driver is 250239281Sgonzo * being activated so IMHO not a big issue. 251239281Sgonzo */ 252239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 253239281Sgonzo 254239281Sgonzo /* Sanity check we managed to find the clock */ 255239281Sgonzo if (clk_dev == NULL) 256239281Sgonzo return (EINVAL); 257239281Sgonzo 258239281Sgonzo /* Activate the clock */ 259239281Sgonzo if (clk_dev->clk_set_source) 260239281Sgonzo ret = clk_dev->clk_set_source(clk_dev, clksrc); 261239281Sgonzo else 262239281Sgonzo ret = EINVAL; 263239281Sgonzo 264239281Sgonzo return (ret); 265239281Sgonzo} 266239281Sgonzo 267239281Sgonzo 268239281Sgonzo/** 269239281Sgonzo * ti_prcm_clk_get_source_freq - gets the source clock frequency 270239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 271239281Sgonzo * of possible modules. 272239281Sgonzo * @freq: pointer to an integer that upon return will contain the src freq 273239281Sgonzo * 274239281Sgonzo * This function returns the frequency of the source clock. 275239281Sgonzo * 276239281Sgonzo * The real work done to enable the clock is really done in the callback 277239281Sgonzo * function associated with the clock, this function is simply a wrapper 278239281Sgonzo * around that. 279239281Sgonzo * 280239281Sgonzo * LOCKING: 281239281Sgonzo * Internally locks the driver context. 282239281Sgonzo * 283239281Sgonzo * RETURNS: 284239281Sgonzo * Returns 0 on success or positive error code on failure. 285239281Sgonzo */ 286239281Sgonzoint 287239281Sgonzoti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq) 288239281Sgonzo{ 289239281Sgonzo struct ti_clock_dev *clk_dev; 290239281Sgonzo int ret; 291239281Sgonzo 292239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 293239281Sgonzo * loop for this, but this function should only called when a driver is 294239281Sgonzo * being activated so IMHO not a big issue. 295239281Sgonzo */ 296239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 297239281Sgonzo 298239281Sgonzo /* Sanity check we managed to find the clock */ 299239281Sgonzo if (clk_dev == NULL) 300239281Sgonzo return (EINVAL); 301239281Sgonzo 302239281Sgonzo /* Get the source frequency of the clock */ 303239281Sgonzo if (clk_dev->clk_get_source_freq) 304239281Sgonzo ret = clk_dev->clk_get_source_freq(clk_dev, freq); 305239281Sgonzo else 306239281Sgonzo ret = EINVAL; 307239281Sgonzo 308239281Sgonzo return (ret); 309239281Sgonzo} 310