Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: mtk-pm-domains: Fix the clock prepared issue

In this new power domain driver, when adding one power domain
it will prepare the dependent clocks at the same.
So we only do clk_bulk_enable/disable control during power ON/OFF.
When system suspend, the pm runtime framework will forcely power off
power domains. However, the dependent clocks are disabled but kept
prepared.

In MediaTek clock drivers, PLL would be turned ON when we do
clk_bulk_prepare control.

Clock hierarchy:
PLL -->
DIV_CK -->
CLK_MUX
(may be dependent clocks)
-->
SUBSYS_CG
(may be dependent clocks)

It will lead some unexpected clock states during system suspend.
This patch will fix by doing prepare_enable/disable_unprepare on
dependent clocks at the same time while we are going to power on/off
any power domain.

Fixes: 59b644b01cf4 ("soc: mediatek: Add MediaTek SCPSYS power domains")
Signed-off-by: Weiyi Lu <weiyi.lu@mediatek.com>
Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
Reviewed-by: chun-jie.chen <chun-jie.chen@mediatek.com>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Link: https://lore.kernel.org/r/20210601035905.2970384-1-hsinyi@chromium.org
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>

authored by

Weiyi Lu and committed by
Matthias Brugger
f0fce06e eed6ff1b

+8 -23
+8 -23
drivers/soc/mediatek/mtk-pm-domains.c
··· 211 211 if (ret) 212 212 return ret; 213 213 214 - ret = clk_bulk_enable(pd->num_clks, pd->clks); 214 + ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks); 215 215 if (ret) 216 216 goto err_reg; 217 217 ··· 229 229 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); 230 230 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); 231 231 232 - ret = clk_bulk_enable(pd->num_subsys_clks, pd->subsys_clks); 232 + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); 233 233 if (ret) 234 234 goto err_pwr_ack; 235 235 ··· 246 246 err_disable_sram: 247 247 scpsys_sram_disable(pd); 248 248 err_disable_subsys_clks: 249 - clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); 249 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 250 250 err_pwr_ack: 251 - clk_bulk_disable(pd->num_clks, pd->clks); 251 + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 252 252 err_reg: 253 253 scpsys_regulator_disable(pd->supply); 254 254 return ret; ··· 269 269 if (ret < 0) 270 270 return ret; 271 271 272 - clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); 272 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 273 273 274 274 /* subsys power off */ 275 275 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); ··· 284 284 if (ret < 0) 285 285 return ret; 286 286 287 - clk_bulk_disable(pd->num_clks, pd->clks); 287 + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 288 288 289 289 scpsys_regulator_disable(pd->supply); 290 290 ··· 410 410 pd->subsys_clks[i].clk = clk; 411 411 } 412 412 413 - ret = clk_bulk_prepare(pd->num_clks, pd->clks); 414 - if (ret) 415 - goto err_put_subsys_clocks; 416 - 417 - ret = clk_bulk_prepare(pd->num_subsys_clks, pd->subsys_clks); 418 - if (ret) 419 - goto err_unprepare_clocks; 420 - 421 413 /* 422 414 * Initially turn on all domains to make the domains usable 423 415 * with !CONFIG_PM and to get the hardware in sync with the ··· 424 432 ret = scpsys_power_on(&pd->genpd); 425 433 if (ret < 0) { 426 434 dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); 427 - goto err_unprepare_clocks; 435 + goto err_put_subsys_clocks; 428 436 } 429 437 } 430 438 ··· 432 440 ret = -EINVAL; 433 441 dev_err(scpsys->dev, 434 442 "power domain with id %d already exists, check your device-tree\n", id); 435 - goto err_unprepare_subsys_clocks; 443 + goto err_put_subsys_clocks; 436 444 } 437 445 438 446 if (!pd->data->name) ··· 452 460 453 461 return scpsys->pd_data.domains[id]; 454 462 455 - err_unprepare_subsys_clocks: 456 - clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); 457 - err_unprepare_clocks: 458 - clk_bulk_unprepare(pd->num_clks, pd->clks); 459 463 err_put_subsys_clocks: 460 464 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); 461 465 err_put_clocks: ··· 530 542 "failed to remove domain '%s' : %d - state may be inconsistent\n", 531 543 pd->genpd.name, ret); 532 544 533 - clk_bulk_unprepare(pd->num_clks, pd->clks); 534 545 clk_bulk_put(pd->num_clks, pd->clks); 535 - 536 - clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); 537 546 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); 538 547 } 539 548