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: releng/10.2/sys/arm/ti/ti_prcm.c 259329 2013-12-13 20:43:11Z ian $"); 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/resource.h> 58239281Sgonzo#include <machine/intr.h> 59239281Sgonzo 60239281Sgonzo#include <arm/ti/ti_prcm.h> 61239281Sgonzo 62239281Sgonzo/** 63239281Sgonzo * ti_clk_devmap - Array of clock devices, should be defined one per SoC 64239281Sgonzo * 65239281Sgonzo * This array is typically defined in one of the targeted *_prcm_clk.c 66239281Sgonzo * files and is specific to the given SoC platform. Each entry in the array 67239281Sgonzo * corresponds to an individual clock device. 68239281Sgonzo */ 69239281Sgonzoextern struct ti_clock_dev ti_clk_devmap[]; 70239281Sgonzo 71239281Sgonzo/** 72239281Sgonzo * ti_prcm_clk_dev - returns a pointer to the clock device with given id 73239281Sgonzo * @clk: the ID of the clock device to get 74239281Sgonzo * 75239281Sgonzo * Simply iterates through the clk_devmap global array and returns a pointer 76239281Sgonzo * to the clock device if found. 77239281Sgonzo * 78239281Sgonzo * LOCKING: 79239281Sgonzo * None 80239281Sgonzo * 81239281Sgonzo * RETURNS: 82239281Sgonzo * The pointer to the clock device on success, on failure NULL is returned. 83239281Sgonzo */ 84239281Sgonzostatic struct ti_clock_dev * 85239281Sgonzoti_prcm_clk_dev(clk_ident_t clk) 86239281Sgonzo{ 87239281Sgonzo struct ti_clock_dev *clk_dev; 88239281Sgonzo 89239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 90239281Sgonzo * loop for this, but this function should only called when a driver is 91239281Sgonzo * being activated so IMHO not a big issue. 92239281Sgonzo */ 93239281Sgonzo clk_dev = &(ti_clk_devmap[0]); 94239281Sgonzo while (clk_dev->id != INVALID_CLK_IDENT) { 95239281Sgonzo if (clk_dev->id == clk) { 96239281Sgonzo return (clk_dev); 97239281Sgonzo } 98239281Sgonzo clk_dev++; 99239281Sgonzo } 100239281Sgonzo 101239281Sgonzo /* Sanity check we managed to find the clock */ 102239281Sgonzo printf("ti_prcm: Failed to find clock device (%d)\n", clk); 103239281Sgonzo return (NULL); 104239281Sgonzo} 105239281Sgonzo 106239281Sgonzo/** 107239281Sgonzo * ti_prcm_clk_valid - enables a clock for a particular module 108239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 109239281Sgonzo * of possible modules. 110239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 111239281Sgonzo * 112239281Sgonzo * This function can enable either a functional or interface clock. 113239281Sgonzo * 114239281Sgonzo * The real work done to enable the clock is really done in the callback 115239281Sgonzo * function associated with the clock, this function is simply a wrapper 116239281Sgonzo * around that. 117239281Sgonzo * 118239281Sgonzo * LOCKING: 119239281Sgonzo * Internally locks the driver context. 120239281Sgonzo * 121239281Sgonzo * RETURNS: 122239281Sgonzo * Returns 0 on success or positive error code on failure. 123239281Sgonzo */ 124239281Sgonzoint 125239281Sgonzoti_prcm_clk_valid(clk_ident_t clk) 126239281Sgonzo{ 127239281Sgonzo int ret = 0; 128239281Sgonzo 129239281Sgonzo if (ti_prcm_clk_dev(clk) == NULL) 130239281Sgonzo ret = EINVAL; 131239281Sgonzo 132239281Sgonzo return (ret); 133239281Sgonzo} 134239281Sgonzo 135239281Sgonzo 136239281Sgonzo/** 137239281Sgonzo * ti_prcm_clk_enable - enables a clock for a particular module 138239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 139239281Sgonzo * of possible modules. 140239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 141239281Sgonzo * 142239281Sgonzo * This function can enable either a functional or interface clock. 143239281Sgonzo * 144239281Sgonzo * The real work done to enable the clock is really done in the callback 145239281Sgonzo * function associated with the clock, this function is simply a wrapper 146239281Sgonzo * around that. 147239281Sgonzo * 148239281Sgonzo * LOCKING: 149239281Sgonzo * Internally locks the driver context. 150239281Sgonzo * 151239281Sgonzo * RETURNS: 152239281Sgonzo * Returns 0 on success or positive error code on failure. 153239281Sgonzo */ 154239281Sgonzoint 155239281Sgonzoti_prcm_clk_enable(clk_ident_t clk) 156239281Sgonzo{ 157239281Sgonzo struct ti_clock_dev *clk_dev; 158239281Sgonzo int ret; 159239281Sgonzo 160239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 161239281Sgonzo * loop for this, but this function should only called when a driver is 162239281Sgonzo * being activated so IMHO not a big issue. 163239281Sgonzo */ 164239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 165239281Sgonzo 166239281Sgonzo /* Sanity check we managed to find the clock */ 167239281Sgonzo if (clk_dev == NULL) 168239281Sgonzo return (EINVAL); 169239281Sgonzo 170239281Sgonzo /* Activate the clock */ 171239281Sgonzo if (clk_dev->clk_activate) 172239281Sgonzo ret = clk_dev->clk_activate(clk_dev); 173239281Sgonzo else 174239281Sgonzo ret = EINVAL; 175239281Sgonzo 176239281Sgonzo return (ret); 177239281Sgonzo} 178239281Sgonzo 179239281Sgonzo 180239281Sgonzo/** 181239281Sgonzo * ti_prcm_clk_disable - disables a clock for a particular module 182239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 183239281Sgonzo * of possible modules. 184239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 185239281Sgonzo * 186239281Sgonzo * This function can enable either a functional or interface clock. 187239281Sgonzo * 188239281Sgonzo * The real work done to enable the clock is really done in the callback 189239281Sgonzo * function associated with the clock, this function is simply a wrapper 190239281Sgonzo * around that. 191239281Sgonzo * 192239281Sgonzo * LOCKING: 193239281Sgonzo * Internally locks the driver context. 194239281Sgonzo * 195239281Sgonzo * RETURNS: 196239281Sgonzo * Returns 0 on success or positive error code on failure. 197239281Sgonzo */ 198239281Sgonzoint 199239281Sgonzoti_prcm_clk_disable(clk_ident_t clk) 200239281Sgonzo{ 201239281Sgonzo struct ti_clock_dev *clk_dev; 202239281Sgonzo int ret; 203239281Sgonzo 204239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 205239281Sgonzo * loop for this, but this function should only called when a driver is 206239281Sgonzo * being activated so IMHO not a big issue. 207239281Sgonzo */ 208239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 209239281Sgonzo 210239281Sgonzo /* Sanity check we managed to find the clock */ 211239281Sgonzo if (clk_dev == NULL) 212239281Sgonzo return (EINVAL); 213239281Sgonzo 214239281Sgonzo /* Activate the clock */ 215239281Sgonzo if (clk_dev->clk_deactivate) 216239281Sgonzo ret = clk_dev->clk_deactivate(clk_dev); 217239281Sgonzo else 218239281Sgonzo ret = EINVAL; 219239281Sgonzo 220239281Sgonzo return (ret); 221239281Sgonzo} 222239281Sgonzo 223239281Sgonzo/** 224239281Sgonzo * ti_prcm_clk_set_source - sets the source 225239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 226239281Sgonzo * of possible modules. 227239281Sgonzo * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. 228239281Sgonzo * 229239281Sgonzo * This function can enable either a functional or interface clock. 230239281Sgonzo * 231239281Sgonzo * The real work done to enable the clock is really done in the callback 232239281Sgonzo * function associated with the clock, this function is simply a wrapper 233239281Sgonzo * around that. 234239281Sgonzo * 235239281Sgonzo * LOCKING: 236239281Sgonzo * Internally locks the driver context. 237239281Sgonzo * 238239281Sgonzo * RETURNS: 239239281Sgonzo * Returns 0 on success or positive error code on failure. 240239281Sgonzo */ 241239281Sgonzoint 242239281Sgonzoti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc) 243239281Sgonzo{ 244239281Sgonzo struct ti_clock_dev *clk_dev; 245239281Sgonzo int ret; 246239281Sgonzo 247239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 248239281Sgonzo * loop for this, but this function should only called when a driver is 249239281Sgonzo * being activated so IMHO not a big issue. 250239281Sgonzo */ 251239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 252239281Sgonzo 253239281Sgonzo /* Sanity check we managed to find the clock */ 254239281Sgonzo if (clk_dev == NULL) 255239281Sgonzo return (EINVAL); 256239281Sgonzo 257239281Sgonzo /* Activate the clock */ 258239281Sgonzo if (clk_dev->clk_set_source) 259239281Sgonzo ret = clk_dev->clk_set_source(clk_dev, clksrc); 260239281Sgonzo else 261239281Sgonzo ret = EINVAL; 262239281Sgonzo 263239281Sgonzo return (ret); 264239281Sgonzo} 265239281Sgonzo 266239281Sgonzo 267239281Sgonzo/** 268239281Sgonzo * ti_prcm_clk_get_source_freq - gets the source clock frequency 269239281Sgonzo * @clk: identifier for the module to enable, see ti_prcm.h for a list 270239281Sgonzo * of possible modules. 271239281Sgonzo * @freq: pointer to an integer that upon return will contain the src freq 272239281Sgonzo * 273239281Sgonzo * This function returns the frequency of the source clock. 274239281Sgonzo * 275239281Sgonzo * The real work done to enable the clock is really done in the callback 276239281Sgonzo * function associated with the clock, this function is simply a wrapper 277239281Sgonzo * around that. 278239281Sgonzo * 279239281Sgonzo * LOCKING: 280239281Sgonzo * Internally locks the driver context. 281239281Sgonzo * 282239281Sgonzo * RETURNS: 283239281Sgonzo * Returns 0 on success or positive error code on failure. 284239281Sgonzo */ 285239281Sgonzoint 286239281Sgonzoti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq) 287239281Sgonzo{ 288239281Sgonzo struct ti_clock_dev *clk_dev; 289239281Sgonzo int ret; 290239281Sgonzo 291239281Sgonzo /* Find the clock within the devmap - it's a bit inefficent having a for 292239281Sgonzo * loop for this, but this function should only called when a driver is 293239281Sgonzo * being activated so IMHO not a big issue. 294239281Sgonzo */ 295239281Sgonzo clk_dev = ti_prcm_clk_dev(clk); 296239281Sgonzo 297239281Sgonzo /* Sanity check we managed to find the clock */ 298239281Sgonzo if (clk_dev == NULL) 299239281Sgonzo return (EINVAL); 300239281Sgonzo 301239281Sgonzo /* Get the source frequency of the clock */ 302239281Sgonzo if (clk_dev->clk_get_source_freq) 303239281Sgonzo ret = clk_dev->clk_get_source_freq(clk_dev, freq); 304239281Sgonzo else 305239281Sgonzo ret = EINVAL; 306239281Sgonzo 307239281Sgonzo return (ret); 308239281Sgonzo} 309