mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
![Stephen Boyd](/assets/img/avatar_default.png)
This kzalloc() could fail. Let's bail out with -ENOMEM here instead of NULL dereferencing. That silences static checkers. We should also cleanup on the error path even though this function returning an error probably means the system won't boot. Cc: Chen-Yu Tsai <wens@csie.org> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
110 lines
2.4 KiB
C
110 lines
2.4 KiB
C
/*
|
|
* Copyright 2016 Maxime Ripard
|
|
*
|
|
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "ccu_common.h"
|
|
#include "ccu_reset.h"
|
|
|
|
static DEFINE_SPINLOCK(ccu_lock);
|
|
|
|
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
|
|
{
|
|
void __iomem *addr;
|
|
u32 reg;
|
|
|
|
if (!lock)
|
|
return;
|
|
|
|
if (common->features & CCU_FEATURE_LOCK_REG)
|
|
addr = common->base + common->lock_reg;
|
|
else
|
|
addr = common->base + common->reg;
|
|
|
|
WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
|
|
}
|
|
|
|
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
|
|
const struct sunxi_ccu_desc *desc)
|
|
{
|
|
struct ccu_reset *reset;
|
|
int i, ret;
|
|
|
|
for (i = 0; i < desc->num_ccu_clks; i++) {
|
|
struct ccu_common *cclk = desc->ccu_clks[i];
|
|
|
|
if (!cclk)
|
|
continue;
|
|
|
|
cclk->base = reg;
|
|
cclk->lock = &ccu_lock;
|
|
}
|
|
|
|
for (i = 0; i < desc->hw_clks->num ; i++) {
|
|
struct clk_hw *hw = desc->hw_clks->hws[i];
|
|
|
|
if (!hw)
|
|
continue;
|
|
|
|
ret = clk_hw_register(NULL, hw);
|
|
if (ret) {
|
|
pr_err("Couldn't register clock %s\n",
|
|
clk_hw_get_name(hw));
|
|
goto err_clk_unreg;
|
|
}
|
|
}
|
|
|
|
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
|
|
desc->hw_clks);
|
|
if (ret)
|
|
goto err_clk_unreg;
|
|
|
|
reset = kzalloc(sizeof(*reset), GFP_KERNEL);
|
|
if (!reset) {
|
|
ret = -ENOMEM;
|
|
goto err_alloc_reset;
|
|
}
|
|
|
|
reset->rcdev.of_node = node;
|
|
reset->rcdev.ops = &ccu_reset_ops;
|
|
reset->rcdev.owner = THIS_MODULE;
|
|
reset->rcdev.nr_resets = desc->num_resets;
|
|
reset->base = reg;
|
|
reset->lock = &ccu_lock;
|
|
reset->reset_map = desc->resets;
|
|
|
|
ret = reset_controller_register(&reset->rcdev);
|
|
if (ret)
|
|
goto err_of_clk_unreg;
|
|
|
|
return 0;
|
|
|
|
err_of_clk_unreg:
|
|
kfree(reset);
|
|
err_alloc_reset:
|
|
of_clk_del_provider(node);
|
|
err_clk_unreg:
|
|
while (--i >= 0) {
|
|
struct clk_hw *hw = desc->hw_clks->hws[i];
|
|
|
|
if (!hw)
|
|
continue;
|
|
clk_hw_unregister(hw);
|
|
}
|
|
return ret;
|
|
}
|