blob: 22d8de21bc42846c20e6ef52d359af6c71e51c46 [file] [log] [blame]
/*
* Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of The Linux Foundation nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <debug.h>
#include <reg.h>
#include <err.h>
#include <limits.h>
#include <bits.h>
#include <clock.h>
#include <string.h>
static struct clk_list msm_clk_list;
int clk_set_parent(struct clk *clk, struct clk *parent)
{
if (!clk->ops->set_parent)
return 0;
return clk->ops->set_parent(clk, parent);
}
struct clk *clk_get_parent(struct clk *clk)
{
if (!clk->ops->get_parent)
return NULL;
return clk->ops->get_parent(clk);
}
int clk_reset(struct clk *clk, enum clk_reset_action action)
{
if (!clk)
return 0;
if (!clk->ops->reset)
return 0;
return clk->ops->reset(clk, action);
}
/*
* Standard clock functions defined in include/clk.h
*/
int clk_enable(struct clk *clk)
{
int ret = 0;
struct clk *parent;
if (!clk)
return 0;
if (clk->count == 0) {
parent = clk_get_parent(clk);
ret = clk_enable(parent);
if (ret)
goto out;
if (clk->ops->enable)
ret = clk->ops->enable(clk);
if (ret) {
clk_disable(parent);
goto out;
}
}
clk->count++;
out:
return ret;
}
void clk_disable(struct clk *clk)
{
struct clk *parent;
if (!clk)
return;
if (clk->count == 0)
goto out;
if (clk->count == 1) {
if (clk->ops->disable)
clk->ops->disable(clk);
parent = clk_get_parent(clk);
clk_disable(parent);
}
clk->count--;
out:
return;
}
unsigned long clk_get_rate(struct clk *clk)
{
if (!clk->ops->get_rate)
return 0;
return clk->ops->get_rate(clk);
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
if (!clk->ops->set_rate)
return ERR_NOT_VALID;
return clk->ops->set_rate(clk, rate);
}
void clk_init(struct clk_lookup *clist, unsigned num)
{
if(clist && num)
{
msm_clk_list.clist = (struct clk_lookup *)clist;
msm_clk_list.num = num;
}
}
struct clk *clk_get (const char * cid)
{
unsigned i;
struct clk_lookup *cl= msm_clk_list.clist;
unsigned num = msm_clk_list.num;
if(!cl || !num)
{
dprintf (CRITICAL, "Alert!! clock list not defined!\n");
return NULL;
}
for(i=0; i < num; i++, cl++)
{
if(!strcmp(cl->con_id, cid))
{
return cl->clk;
}
}
dprintf(CRITICAL, "Alert!! Requested clock \"%s\" is not supported!\n", cid);
return NULL;
}
int clk_get_set_enable(char *id, unsigned long rate, bool enable)
{
int ret = NO_ERROR;
struct clk *cp;
/* Get clk */
cp = clk_get(id);
if(!cp)
{
dprintf(CRITICAL, "Can't find clock with id: %s\n", id);
ret = ERR_NOT_VALID;
goto get_set_enable_error;
}
/* Set rate */
if(rate)
{
ret = clk_set_rate(cp, rate);
if(ret)
{
dprintf(CRITICAL, "Clock set rate failed.\n");
goto get_set_enable_error;
}
}
/* Enable clock */
if(enable)
{
ret = clk_enable(cp);
if(ret)
{
dprintf(CRITICAL, "Clock enable failed.\n");
}
}
get_set_enable_error:
return ret;
}
#ifdef DEBUG_CLOCK
struct clk_list *clk_get_list()
{
return &msm_clk_list;
}
#endif