Lines Matching +full:power +full:-
1 // SPDX-License-Identifier: GPL-2.0+
3 * Power domain driver for Broadcom BCM2835
8 #include <dt-bindings/soc/bcm2835-pm.h>
12 #include <linux/mfd/bcm2835-pm.h>
16 #include <linux/reset-controller.h>
61 /* The power gates must be enabled with this bit before enabling the LDO in the
109 #define PM_READ(reg) readl(power->base + (reg))
110 #define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
133 struct bcm2835_power *power; member
152 static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable) in bcm2835_asb_control() argument
154 void __iomem *base = power->asb; in bcm2835_asb_control()
163 if (power->rpivid_asb) in bcm2835_asb_control()
164 base = power->rpivid_asb; in bcm2835_asb_control()
180 if (ktime_get_ns() - start >= 1000) in bcm2835_asb_control()
181 return -ETIMEDOUT; in bcm2835_asb_control()
187 static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) in bcm2835_asb_enable() argument
189 return bcm2835_asb_control(power, reg, true); in bcm2835_asb_enable()
192 static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) in bcm2835_asb_disable() argument
194 return bcm2835_asb_control(power, reg, false); in bcm2835_asb_disable()
199 struct bcm2835_power *power = pd->power; in bcm2835_power_power_off() local
202 if (power->rpivid_asb) in bcm2835_power_power_off()
211 /* Open the power switches. */ in bcm2835_power_power_off()
219 struct bcm2835_power *power = pd->power; in bcm2835_power_power_on() local
220 struct device *dev = power->dev; in bcm2835_power_power_on()
227 if (power->rpivid_asb) in bcm2835_power_power_on()
234 /* Enable power. Allowing too much current at once may result in bcm2835_power_power_on()
248 if (ktime_get_ns() - start >= 3000) in bcm2835_power_power_on()
253 dev_err(dev, "Timeout waiting for %s power OK\n", in bcm2835_power_power_on()
254 pd->base.name); in bcm2835_power_power_on()
255 ret = -ETIMEDOUT; in bcm2835_power_power_on()
267 if (ktime_get_ns() - start >= 1000) { in bcm2835_power_power_on()
269 pd->base.name); in bcm2835_power_power_on()
270 ret = -ETIMEDOUT; in bcm2835_power_power_on()
293 struct bcm2835_power *power = pd->power; in bcm2835_asb_power_on() local
296 ret = clk_prepare_enable(pd->clk); in bcm2835_asb_power_on()
298 dev_err(power->dev, "Failed to enable clock for %s\n", in bcm2835_asb_power_on()
299 pd->base.name); in bcm2835_asb_power_on()
306 clk_disable_unprepare(pd->clk); in bcm2835_asb_power_on()
311 ret = clk_prepare_enable(pd->clk); in bcm2835_asb_power_on()
313 dev_err(power->dev, "Failed to enable clock for %s\n", in bcm2835_asb_power_on()
314 pd->base.name); in bcm2835_asb_power_on()
318 ret = bcm2835_asb_enable(power, asb_m_reg); in bcm2835_asb_power_on()
320 dev_err(power->dev, "Failed to enable ASB master for %s\n", in bcm2835_asb_power_on()
321 pd->base.name); in bcm2835_asb_power_on()
324 ret = bcm2835_asb_enable(power, asb_s_reg); in bcm2835_asb_power_on()
326 dev_err(power->dev, "Failed to enable ASB slave for %s\n", in bcm2835_asb_power_on()
327 pd->base.name); in bcm2835_asb_power_on()
334 bcm2835_asb_disable(power, asb_m_reg); in bcm2835_asb_power_on()
336 clk_disable_unprepare(pd->clk); in bcm2835_asb_power_on()
348 struct bcm2835_power *power = pd->power; in bcm2835_asb_power_off() local
351 ret = bcm2835_asb_disable(power, asb_s_reg); in bcm2835_asb_power_off()
353 dev_warn(power->dev, "Failed to disable ASB slave for %s\n", in bcm2835_asb_power_off()
354 pd->base.name); in bcm2835_asb_power_off()
357 ret = bcm2835_asb_disable(power, asb_m_reg); in bcm2835_asb_power_off()
359 dev_warn(power->dev, "Failed to disable ASB master for %s\n", in bcm2835_asb_power_off()
360 pd->base.name); in bcm2835_asb_power_off()
361 bcm2835_asb_enable(power, asb_s_reg); in bcm2835_asb_power_off()
365 clk_disable_unprepare(pd->clk); in bcm2835_asb_power_off()
377 struct bcm2835_power *power = pd->power; in bcm2835_power_pd_power_on() local
379 switch (pd->domain) { in bcm2835_power_pd_power_on()
434 dev_err(power->dev, "Invalid domain %d\n", pd->domain); in bcm2835_power_pd_power_on()
435 return -EINVAL; in bcm2835_power_pd_power_on()
443 struct bcm2835_power *power = pd->power; in bcm2835_power_pd_power_off() local
445 switch (pd->domain) { in bcm2835_power_pd_power_off()
497 dev_err(power->dev, "Invalid domain %d\n", pd->domain); in bcm2835_power_pd_power_off()
498 return -EINVAL; in bcm2835_power_pd_power_off()
503 bcm2835_init_power_domain(struct bcm2835_power *power, in bcm2835_init_power_domain() argument
506 struct device *dev = power->dev; in bcm2835_init_power_domain()
507 struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; in bcm2835_init_power_domain()
509 dom->clk = devm_clk_get(dev->parent, name); in bcm2835_init_power_domain()
510 if (IS_ERR(dom->clk)) { in bcm2835_init_power_domain()
511 int ret = PTR_ERR(dom->clk); in bcm2835_init_power_domain()
513 if (ret == -EPROBE_DEFER) in bcm2835_init_power_domain()
519 dom->clk = NULL; in bcm2835_init_power_domain()
522 dom->base.name = name; in bcm2835_init_power_domain()
523 dom->base.power_on = bcm2835_power_pd_power_on; in bcm2835_init_power_domain()
524 dom->base.power_off = bcm2835_power_pd_power_off; in bcm2835_init_power_domain()
526 dom->domain = pd_xlate_index; in bcm2835_init_power_domain()
527 dom->power = power; in bcm2835_init_power_domain()
530 pm_genpd_init(&dom->base, NULL, true); in bcm2835_init_power_domain()
532 power->pd_xlate.domains[pd_xlate_index] = &dom->base; in bcm2835_init_power_domain()
537 /** bcm2835_reset_reset - Resets a block that has a reset line in the
540 * The consumer of the reset controller must have the power domain up
541 * -- there's no reset ability with the power domain down. To reset
542 * the sub-block, we just disable its access to memory through the
543 * ASB, reset, and re-enable.
548 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, in bcm2835_reset_reset() local
555 pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D]; in bcm2835_reset_reset()
558 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264]; in bcm2835_reset_reset()
561 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP]; in bcm2835_reset_reset()
564 dev_err(power->dev, "Bad reset id %ld\n", id); in bcm2835_reset_reset()
565 return -EINVAL; in bcm2835_reset_reset()
568 ret = bcm2835_power_pd_power_off(&pd->base); in bcm2835_reset_reset()
572 return bcm2835_power_pd_power_on(&pd->base); in bcm2835_reset_reset()
578 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, in bcm2835_reset_status() local
589 return -EINVAL; in bcm2835_reset_status()
618 struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent); in bcm2835_power_probe()
619 struct device *dev = &pdev->dev; in bcm2835_power_probe()
620 struct bcm2835_power *power; in bcm2835_power_probe() local
635 power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); in bcm2835_power_probe()
636 if (!power) in bcm2835_power_probe()
637 return -ENOMEM; in bcm2835_power_probe()
638 platform_set_drvdata(pdev, power); in bcm2835_power_probe()
640 power->dev = dev; in bcm2835_power_probe()
641 power->base = pm->base; in bcm2835_power_probe()
642 power->asb = pm->asb; in bcm2835_power_probe()
643 power->rpivid_asb = pm->rpivid_asb; in bcm2835_power_probe()
645 id = readl(power->asb + ASB_AXI_BRDG_ID); in bcm2835_power_probe()
648 return -ENODEV; in bcm2835_power_probe()
651 if (power->rpivid_asb) { in bcm2835_power_probe()
652 id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); in bcm2835_power_probe()
656 return -ENODEV; in bcm2835_power_probe()
660 power->pd_xlate.domains = devm_kcalloc(dev, in bcm2835_power_probe()
662 sizeof(*power->pd_xlate.domains), in bcm2835_power_probe()
664 if (!power->pd_xlate.domains) in bcm2835_power_probe()
665 return -ENOMEM; in bcm2835_power_probe()
667 power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); in bcm2835_power_probe()
670 ret = bcm2835_init_power_domain(power, i, power_domain_names[i]); in bcm2835_power_probe()
676 pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, in bcm2835_power_probe()
677 &power->domains[domain_deps[i].child].base); in bcm2835_power_probe()
680 power->reset.owner = THIS_MODULE; in bcm2835_power_probe()
681 power->reset.nr_resets = BCM2835_RESET_COUNT; in bcm2835_power_probe()
682 power->reset.ops = &bcm2835_reset_ops; in bcm2835_power_probe()
683 power->reset.of_node = dev->parent->of_node; in bcm2835_power_probe()
685 ret = devm_reset_controller_register(dev, &power->reset); in bcm2835_power_probe()
689 of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate); in bcm2835_power_probe()
691 dev_info(dev, "Broadcom BCM2835 power domains driver"); in bcm2835_power_probe()
696 struct generic_pm_domain *dom = &power->domains[i].base; in bcm2835_power_probe()
698 if (dom->name) in bcm2835_power_probe()
707 .name = "bcm2835-power",
713 MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");