|
@@ -67,7 +67,7 @@ struct rockchip_pm_domain {
|
|
|
struct regmap **qos_regmap;
|
|
|
u32 *qos_save_regs[MAX_QOS_REGS_NUM];
|
|
|
int num_clks;
|
|
|
- struct clk *clks[];
|
|
|
+ struct clk_bulk_data *clks;
|
|
|
};
|
|
|
|
|
|
struct rockchip_pmu {
|
|
@@ -274,13 +274,18 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
|
|
|
|
|
static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
|
|
{
|
|
|
- int i;
|
|
|
+ struct rockchip_pmu *pmu = pd->pmu;
|
|
|
+ int ret;
|
|
|
|
|
|
- mutex_lock(&pd->pmu->mutex);
|
|
|
+ mutex_lock(&pmu->mutex);
|
|
|
|
|
|
if (rockchip_pmu_domain_is_on(pd) != power_on) {
|
|
|
- for (i = 0; i < pd->num_clks; i++)
|
|
|
- clk_enable(pd->clks[i]);
|
|
|
+ ret = clk_bulk_enable(pd->num_clks, pd->clks);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(pmu->dev, "failed to enable clocks\n");
|
|
|
+ mutex_unlock(&pmu->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
if (!power_on) {
|
|
|
rockchip_pmu_save_qos(pd);
|
|
@@ -298,11 +303,10 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
|
|
rockchip_pmu_restore_qos(pd);
|
|
|
}
|
|
|
|
|
|
- for (i = pd->num_clks - 1; i >= 0; i--)
|
|
|
- clk_disable(pd->clks[i]);
|
|
|
+ clk_bulk_disable(pd->num_clks, pd->clks);
|
|
|
}
|
|
|
|
|
|
- mutex_unlock(&pd->pmu->mutex);
|
|
|
+ mutex_unlock(&pmu->mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -364,8 +368,6 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
const struct rockchip_domain_info *pd_info;
|
|
|
struct rockchip_pm_domain *pd;
|
|
|
struct device_node *qos_node;
|
|
|
- struct clk *clk;
|
|
|
- int clk_cnt;
|
|
|
int i, j;
|
|
|
u32 id;
|
|
|
int error;
|
|
@@ -391,41 +393,41 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells");
|
|
|
- pd = devm_kzalloc(pmu->dev,
|
|
|
- sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]),
|
|
|
- GFP_KERNEL);
|
|
|
+ pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
|
|
|
if (!pd)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
pd->info = pd_info;
|
|
|
pd->pmu = pmu;
|
|
|
|
|
|
- for (i = 0; i < clk_cnt; i++) {
|
|
|
- clk = of_clk_get(node, i);
|
|
|
- if (IS_ERR(clk)) {
|
|
|
- error = PTR_ERR(clk);
|
|
|
+ pd->num_clks = of_count_phandle_with_args(node, "clocks",
|
|
|
+ "#clock-cells");
|
|
|
+ if (pd->num_clks > 0) {
|
|
|
+ pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
|
|
|
+ sizeof(*pd->clks), GFP_KERNEL);
|
|
|
+ if (!pd->clks)
|
|
|
+ return -ENOMEM;
|
|
|
+ } else {
|
|
|
+ dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n",
|
|
|
+ node->name, pd->num_clks);
|
|
|
+ pd->num_clks = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < pd->num_clks; i++) {
|
|
|
+ pd->clks[i].clk = of_clk_get(node, i);
|
|
|
+ if (IS_ERR(pd->clks[i].clk)) {
|
|
|
+ error = PTR_ERR(pd->clks[i].clk);
|
|
|
dev_err(pmu->dev,
|
|
|
"%s: failed to get clk at index %d: %d\n",
|
|
|
node->name, i, error);
|
|
|
- goto err_out;
|
|
|
- }
|
|
|
-
|
|
|
- error = clk_prepare(clk);
|
|
|
- if (error) {
|
|
|
- dev_err(pmu->dev,
|
|
|
- "%s: failed to prepare clk %pC (index %d): %d\n",
|
|
|
- node->name, clk, i, error);
|
|
|
- clk_put(clk);
|
|
|
- goto err_out;
|
|
|
+ return error;
|
|
|
}
|
|
|
-
|
|
|
- pd->clks[pd->num_clks++] = clk;
|
|
|
-
|
|
|
- dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n",
|
|
|
- clk, node->name);
|
|
|
}
|
|
|
|
|
|
+ error = clk_bulk_prepare(pd->num_clks, pd->clks);
|
|
|
+ if (error)
|
|
|
+ goto err_put_clocks;
|
|
|
+
|
|
|
pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
|
|
|
NULL);
|
|
|
|
|
@@ -435,7 +437,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
GFP_KERNEL);
|
|
|
if (!pd->qos_regmap) {
|
|
|
error = -ENOMEM;
|
|
|
- goto err_out;
|
|
|
+ goto err_unprepare_clocks;
|
|
|
}
|
|
|
|
|
|
for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
|
|
@@ -445,7 +447,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
GFP_KERNEL);
|
|
|
if (!pd->qos_save_regs[j]) {
|
|
|
error = -ENOMEM;
|
|
|
- goto err_out;
|
|
|
+ goto err_unprepare_clocks;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -453,13 +455,13 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
qos_node = of_parse_phandle(node, "pm_qos", j);
|
|
|
if (!qos_node) {
|
|
|
error = -ENODEV;
|
|
|
- goto err_out;
|
|
|
+ goto err_unprepare_clocks;
|
|
|
}
|
|
|
pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
|
|
|
if (IS_ERR(pd->qos_regmap[j])) {
|
|
|
error = -ENODEV;
|
|
|
of_node_put(qos_node);
|
|
|
- goto err_out;
|
|
|
+ goto err_unprepare_clocks;
|
|
|
}
|
|
|
of_node_put(qos_node);
|
|
|
}
|
|
@@ -470,7 +472,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
dev_err(pmu->dev,
|
|
|
"failed to power on domain '%s': %d\n",
|
|
|
node->name, error);
|
|
|
- goto err_out;
|
|
|
+ goto err_unprepare_clocks;
|
|
|
}
|
|
|
|
|
|
pd->genpd.name = node->name;
|
|
@@ -486,17 +488,16 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|
|
pmu->genpd_data.domains[id] = &pd->genpd;
|
|
|
return 0;
|
|
|
|
|
|
-err_out:
|
|
|
- while (--i >= 0) {
|
|
|
- clk_unprepare(pd->clks[i]);
|
|
|
- clk_put(pd->clks[i]);
|
|
|
- }
|
|
|
+err_unprepare_clocks:
|
|
|
+ clk_bulk_unprepare(pd->num_clks, pd->clks);
|
|
|
+err_put_clocks:
|
|
|
+ clk_bulk_put(pd->num_clks, pd->clks);
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
|
|
|
{
|
|
|
- int i, ret;
|
|
|
+ int ret;
|
|
|
|
|
|
/*
|
|
|
* We're in the error cleanup already, so we only complain,
|
|
@@ -507,10 +508,8 @@ static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
|
|
|
dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
|
|
|
pd->genpd.name, ret);
|
|
|
|
|
|
- for (i = 0; i < pd->num_clks; i++) {
|
|
|
- clk_unprepare(pd->clks[i]);
|
|
|
- clk_put(pd->clks[i]);
|
|
|
- }
|
|
|
+ clk_bulk_unprepare(pd->num_clks, pd->clks);
|
|
|
+ clk_bulk_put(pd->num_clks, pd->clks);
|
|
|
|
|
|
/* protect the zeroing of pm->num_clks */
|
|
|
mutex_lock(&pd->pmu->mutex);
|