Merge branches 'clk-tegra' and 'clk-bulk-get-all' into clk-next
- Nvidia Tegra clk driver MBIST workaround fix - clk_bulk_get_all() API and friends to get all the clks for a device * clk-tegra: clk: tegra210: Include size.h for compilation ease clk: tegra: Fixes for MBIST work around clk: tegra: probe deferral error reporting * clk-bulk-get-all: clk: add managed version of clk_bulk_get_all clk: add new APIs to operate on all available clocks clk: bulk: add of_clk_bulk_get()
This commit is contained in:
commit
c1f74dbe59
@ -17,8 +17,65 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
|
||||||
|
struct clk_bulk_data *clks)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_clks; i++)
|
||||||
|
clks[i].clk = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < num_clks; i++) {
|
||||||
|
clks[i].clk = of_clk_get(np, i);
|
||||||
|
if (IS_ERR(clks[i].clk)) {
|
||||||
|
ret = PTR_ERR(clks[i].clk);
|
||||||
|
pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
|
||||||
|
np, i, ret);
|
||||||
|
clks[i].clk = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
clk_bulk_put(i, clks);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __must_check of_clk_bulk_get_all(struct device_node *np,
|
||||||
|
struct clk_bulk_data **clks)
|
||||||
|
{
|
||||||
|
struct clk_bulk_data *clk_bulk;
|
||||||
|
int num_clks;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
num_clks = of_clk_get_parent_count(np);
|
||||||
|
if (!num_clks)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
|
||||||
|
if (!clk_bulk)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = of_clk_bulk_get(np, num_clks, clk_bulk);
|
||||||
|
if (ret) {
|
||||||
|
kfree(clk_bulk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*clks = clk_bulk;
|
||||||
|
|
||||||
|
return num_clks;
|
||||||
|
}
|
||||||
|
|
||||||
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
|
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
|
||||||
{
|
{
|
||||||
@ -59,6 +116,29 @@ err:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(clk_bulk_get);
|
EXPORT_SYMBOL(clk_bulk_get);
|
||||||
|
|
||||||
|
void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
|
||||||
|
{
|
||||||
|
if (IS_ERR_OR_NULL(clks))
|
||||||
|
return;
|
||||||
|
|
||||||
|
clk_bulk_put(num_clks, clks);
|
||||||
|
|
||||||
|
kfree(clks);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(clk_bulk_put_all);
|
||||||
|
|
||||||
|
int __must_check clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks)
|
||||||
|
{
|
||||||
|
struct device_node *np = dev_of_node(dev);
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return of_clk_bulk_get_all(np, clks);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(clk_bulk_get_all);
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_CLK_PREPARE
|
#ifdef CONFIG_HAVE_CLK_PREPARE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,6 +70,30 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
|
EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
|
||||||
|
|
||||||
|
int __must_check devm_clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks)
|
||||||
|
{
|
||||||
|
struct clk_bulk_devres *devres;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
devres = devres_alloc(devm_clk_bulk_release,
|
||||||
|
sizeof(*devres), GFP_KERNEL);
|
||||||
|
if (!devres)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = clk_bulk_get_all(dev, &devres->clks);
|
||||||
|
if (ret > 0) {
|
||||||
|
*clks = devres->clks;
|
||||||
|
devres->num_clks = ret;
|
||||||
|
devres_add(dev, devres);
|
||||||
|
} else {
|
||||||
|
devres_free(devres);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
|
||||||
|
|
||||||
static int devm_clk_match(struct device *dev, void *res, void *data)
|
static int devm_clk_match(struct device *dev, void *res, void *data)
|
||||||
{
|
{
|
||||||
struct clk **c = res;
|
struct clk **c = res;
|
||||||
|
@ -1609,8 +1609,12 @@ int tegra_dfll_register(struct platform_device *pdev,
|
|||||||
|
|
||||||
td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
|
td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
|
||||||
if (IS_ERR(td->vdd_reg)) {
|
if (IS_ERR(td->vdd_reg)) {
|
||||||
dev_err(td->dev, "couldn't get vdd_cpu regulator\n");
|
ret = PTR_ERR(td->vdd_reg);
|
||||||
return PTR_ERR(td->vdd_reg);
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(td->dev, "couldn't get vdd_cpu regulator: %d\n",
|
||||||
|
ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
|
td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <dt-bindings/clock/tegra210-car.h>
|
#include <dt-bindings/clock/tegra210-car.h>
|
||||||
#include <dt-bindings/reset/tegra210-car.h>
|
#include <dt-bindings/reset/tegra210-car.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
#include <soc/tegra/pmc.h>
|
#include <soc/tegra/pmc.h>
|
||||||
|
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
@ -2603,7 +2604,7 @@ static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = {
|
|||||||
[TEGRA_POWERGATE_MPE] = {
|
[TEGRA_POWERGATE_MPE] = {
|
||||||
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
||||||
.lvl2_offset = LVL2_CLK_GATE_OVRE,
|
.lvl2_offset = LVL2_CLK_GATE_OVRE,
|
||||||
.lvl2_mask = BIT(2),
|
.lvl2_mask = BIT(29),
|
||||||
},
|
},
|
||||||
[TEGRA_POWERGATE_SOR] = {
|
[TEGRA_POWERGATE_SOR] = {
|
||||||
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
||||||
@ -2654,14 +2655,14 @@ static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = {
|
|||||||
.num_clks = ARRAY_SIZE(nvdec_slcg_clkids),
|
.num_clks = ARRAY_SIZE(nvdec_slcg_clkids),
|
||||||
.clk_init_data = nvdec_slcg_clkids,
|
.clk_init_data = nvdec_slcg_clkids,
|
||||||
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
||||||
.lvl2_offset = LVL2_CLK_GATE_OVRC,
|
.lvl2_offset = LVL2_CLK_GATE_OVRE,
|
||||||
.lvl2_mask = BIT(9) | BIT(31),
|
.lvl2_mask = BIT(9) | BIT(31),
|
||||||
},
|
},
|
||||||
[TEGRA_POWERGATE_NVJPG] = {
|
[TEGRA_POWERGATE_NVJPG] = {
|
||||||
.num_clks = ARRAY_SIZE(nvjpg_slcg_clkids),
|
.num_clks = ARRAY_SIZE(nvjpg_slcg_clkids),
|
||||||
.clk_init_data = nvjpg_slcg_clkids,
|
.clk_init_data = nvjpg_slcg_clkids,
|
||||||
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
.handle_lvl2_ovr = tegra210_generic_mbist_war,
|
||||||
.lvl2_offset = LVL2_CLK_GATE_OVRC,
|
.lvl2_offset = LVL2_CLK_GATE_OVRE,
|
||||||
.lvl2_mask = BIT(9) | BIT(31),
|
.lvl2_mask = BIT(9) | BIT(31),
|
||||||
},
|
},
|
||||||
[TEGRA_POWERGATE_AUD] = {
|
[TEGRA_POWERGATE_AUD] = {
|
||||||
|
@ -312,7 +312,26 @@ struct clk *clk_get(struct device *dev, const char *id);
|
|||||||
*/
|
*/
|
||||||
int __must_check clk_bulk_get(struct device *dev, int num_clks,
|
int __must_check clk_bulk_get(struct device *dev, int num_clks,
|
||||||
struct clk_bulk_data *clks);
|
struct clk_bulk_data *clks);
|
||||||
|
/**
|
||||||
|
* clk_bulk_get_all - lookup and obtain all available references to clock
|
||||||
|
* producer.
|
||||||
|
* @dev: device for clock "consumer"
|
||||||
|
* @clks: pointer to the clk_bulk_data table of consumer
|
||||||
|
*
|
||||||
|
* This helper function allows drivers to get all clk consumers in one
|
||||||
|
* operation. If any of the clk cannot be acquired then any clks
|
||||||
|
* that were obtained will be freed before returning to the caller.
|
||||||
|
*
|
||||||
|
* Returns a positive value for the number of clocks obtained while the
|
||||||
|
* clock references are stored in the clk_bulk_data table in @clks field.
|
||||||
|
* Returns 0 if there're none and a negative value if something failed.
|
||||||
|
*
|
||||||
|
* Drivers must assume that the clock source is not enabled.
|
||||||
|
*
|
||||||
|
* clk_bulk_get should not be called from within interrupt context.
|
||||||
|
*/
|
||||||
|
int __must_check clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks);
|
||||||
/**
|
/**
|
||||||
* devm_clk_bulk_get - managed get multiple clk consumers
|
* devm_clk_bulk_get - managed get multiple clk consumers
|
||||||
* @dev: device for clock "consumer"
|
* @dev: device for clock "consumer"
|
||||||
@ -327,6 +346,22 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
|
|||||||
*/
|
*/
|
||||||
int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
|
int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
|
||||||
struct clk_bulk_data *clks);
|
struct clk_bulk_data *clks);
|
||||||
|
/**
|
||||||
|
* devm_clk_bulk_get_all - managed get multiple clk consumers
|
||||||
|
* @dev: device for clock "consumer"
|
||||||
|
* @clks: pointer to the clk_bulk_data table of consumer
|
||||||
|
*
|
||||||
|
* Returns a positive value for the number of clocks obtained while the
|
||||||
|
* clock references are stored in the clk_bulk_data table in @clks field.
|
||||||
|
* Returns 0 if there're none and a negative value if something failed.
|
||||||
|
*
|
||||||
|
* This helper function allows drivers to get several clk
|
||||||
|
* consumers in one operation with management, the clks will
|
||||||
|
* automatically be freed when the device is unbound.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int __must_check devm_clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_clk_get - lookup and obtain a managed reference to a clock producer.
|
* devm_clk_get - lookup and obtain a managed reference to a clock producer.
|
||||||
@ -487,6 +522,19 @@ void clk_put(struct clk *clk);
|
|||||||
*/
|
*/
|
||||||
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks);
|
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clk_bulk_put_all - "free" all the clock source
|
||||||
|
* @num_clks: the number of clk_bulk_data
|
||||||
|
* @clks: the clk_bulk_data table of consumer
|
||||||
|
*
|
||||||
|
* Note: drivers must ensure that all clk_bulk_enable calls made on this
|
||||||
|
* clock source are balanced by clk_bulk_disable calls prior to calling
|
||||||
|
* this function.
|
||||||
|
*
|
||||||
|
* clk_bulk_put_all should not be called from within interrupt context.
|
||||||
|
*/
|
||||||
|
void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_clk_put - "free" a managed clock source
|
* devm_clk_put - "free" a managed clock source
|
||||||
* @dev: device used to acquire the clock
|
* @dev: device used to acquire the clock
|
||||||
@ -659,6 +707,12 @@ static inline int __must_check clk_bulk_get(struct device *dev, int num_clks,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int __must_check clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct clk *devm_clk_get(struct device *dev, const char *id)
|
static inline struct clk *devm_clk_get(struct device *dev, const char *id)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -670,6 +724,13 @@ static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clk
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int __must_check devm_clk_bulk_get_all(struct device *dev,
|
||||||
|
struct clk_bulk_data **clks)
|
||||||
|
{
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct clk *devm_get_clk_from_child(struct device *dev,
|
static inline struct clk *devm_get_clk_from_child(struct device *dev,
|
||||||
struct device_node *np, const char *con_id)
|
struct device_node *np, const char *con_id)
|
||||||
{
|
{
|
||||||
@ -680,6 +741,8 @@ static inline void clk_put(struct clk *clk) {}
|
|||||||
|
|
||||||
static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {}
|
static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {}
|
||||||
|
|
||||||
|
static inline void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) {}
|
||||||
|
|
||||||
static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
|
static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user