blob: 5f4e8f28edea35d38a26a260db87645b76fae59a [file] [log] [blame]
/*
* Copyright (C) 2014 Google, Inc.
* Copyright (C) 2014 Imagination Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*
* TZ1090 Clocks
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include "clk.h"
struct tz1090_clk_provider *tz1090_clk_alloc_provider(struct device_node *node,
unsigned int num_clks)
{
struct tz1090_clk_provider *p;
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return p;
p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL);
if (!p->clk_data.clks)
goto free_provider;
p->clk_data.clk_num = num_clks;
p->node = node;
p->base = of_iomap(node, 0);
if (!p->base) {
pr_err("%s: Failed to map clock provider registers\n",
node->full_name);
goto free_clks;
}
return p;
free_clks:
kfree(p->clk_data.clks);
free_provider:
kfree(p);
return NULL;
}
const char *tz1090_clk_xlate(struct tz1090_clk_provider *p,
const char *clk_name)
{
/*
* If clock name begins with @, the rest refers to an external clock.
*
* Look for the index of the parent clock with a matching label in
* clock-names. If found, find the name of the specified parent clock.
*
* If not found, we leave it unchanged. The @ at the beginning should
* ensure it doesn't accidentally match a real clock.
*/
if (*clk_name == '@') {
const char *clk_label = clk_name + 1;
int idx = of_property_match_string(p->node, "clock-names",
clk_label);
if (idx >= 0) {
clk_name = of_clk_get_parent_name(p->node, idx);
pr_debug("%s: Parent clock '%s' found as '%s'\n",
p->node->full_name, clk_label, clk_name);
} else {
pr_err("%s: No parent clock '%s' found\n",
p->node->full_name, clk_label);
}
}
return clk_name;
}
void tz1090_clk_register_provider(struct tz1090_clk_provider *p)
{
unsigned int i;
for (i = 0; i < p->clk_data.clk_num; i++)
if (IS_ERR(p->clk_data.clks[i]))
pr_warn("%s: Failed to register clock %d: %ld\n",
p->node->full_name, i,
PTR_ERR(p->clk_data.clks[i]));
of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data);
}