brintos

brintos / linux-shallow public Read only

0
0
Text · 17.8 KiB · d2f0233 Raw
714 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Power domain driver for Broadcom BCM28354 *5 * Copyright (C) 2018 Broadcom6 */7 8#include <dt-bindings/soc/bcm2835-pm.h>9#include <linux/clk.h>10#include <linux/delay.h>11#include <linux/io.h>12#include <linux/mfd/bcm2835-pm.h>13#include <linux/module.h>14#include <linux/platform_device.h>15#include <linux/pm_domain.h>16#include <linux/reset-controller.h>17#include <linux/types.h>18 19#define PM_GNRIC                        0x0020#define PM_AUDIO                        0x0421#define PM_STATUS                       0x1822#define PM_RSTC				0x1c23#define PM_RSTS				0x2024#define PM_WDOG				0x2425#define PM_PADS0			0x2826#define PM_PADS2			0x2c27#define PM_PADS3			0x3028#define PM_PADS4			0x3429#define PM_PADS5			0x3830#define PM_PADS6			0x3c31#define PM_CAM0				0x4432#define PM_CAM0_LDOHPEN			BIT(2)33#define PM_CAM0_LDOLPEN			BIT(1)34#define PM_CAM0_CTRLEN			BIT(0)35 36#define PM_CAM1				0x4837#define PM_CAM1_LDOHPEN			BIT(2)38#define PM_CAM1_LDOLPEN			BIT(1)39#define PM_CAM1_CTRLEN			BIT(0)40 41#define PM_CCP2TX			0x4c42#define PM_CCP2TX_LDOEN			BIT(1)43#define PM_CCP2TX_CTRLEN		BIT(0)44 45#define PM_DSI0				0x5046#define PM_DSI0_LDOHPEN			BIT(2)47#define PM_DSI0_LDOLPEN			BIT(1)48#define PM_DSI0_CTRLEN			BIT(0)49 50#define PM_DSI1				0x5451#define PM_DSI1_LDOHPEN			BIT(2)52#define PM_DSI1_LDOLPEN			BIT(1)53#define PM_DSI1_CTRLEN			BIT(0)54 55#define PM_HDMI				0x5856#define PM_HDMI_RSTDR			BIT(19)57#define PM_HDMI_LDOPD			BIT(1)58#define PM_HDMI_CTRLEN			BIT(0)59 60#define PM_USB				0x5c61/* The power gates must be enabled with this bit before enabling the LDO in the62 * USB block.63 */64#define PM_USB_CTRLEN			BIT(0)65 66#define PM_PXLDO			0x6067#define PM_PXBG				0x6468#define PM_DFT				0x6869#define PM_SMPS				0x6c70#define PM_XOSC				0x7071#define PM_SPAREW			0x7472#define PM_SPARER			0x7873#define PM_AVS_RSTDR			0x7c74#define PM_AVS_STAT			0x8075#define PM_AVS_EVENT			0x8476#define PM_AVS_INTEN			0x8877#define PM_DUMMY			0xfc78 79#define PM_IMAGE			0x10880#define PM_GRAFX			0x10c81#define PM_PROC				0x11082#define PM_ENAB				BIT(12)83#define PM_ISPRSTN			BIT(8)84#define PM_H264RSTN			BIT(7)85#define PM_PERIRSTN			BIT(6)86#define PM_V3DRSTN			BIT(6)87#define PM_ISFUNC			BIT(5)88#define PM_MRDONE			BIT(4)89#define PM_MEMREP			BIT(3)90#define PM_ISPOW			BIT(2)91#define PM_POWOK			BIT(1)92#define PM_POWUP			BIT(0)93#define PM_INRUSH_SHIFT			1394#define PM_INRUSH_3_5_MA		095#define PM_INRUSH_5_MA			196#define PM_INRUSH_10_MA			297#define PM_INRUSH_20_MA			398#define PM_INRUSH_MASK			(3 << PM_INRUSH_SHIFT)99 100#define PM_PASSWORD			0x5a000000101 102#define PM_WDOG_TIME_SET		0x000fffff103#define PM_RSTC_WRCFG_CLR		0xffffffcf104#define PM_RSTS_HADWRH_SET		0x00000040105#define PM_RSTC_WRCFG_SET		0x00000030106#define PM_RSTC_WRCFG_FULL_RESET	0x00000020107#define PM_RSTC_RESET			0x00000102108 109#define PM_READ(reg) readl(power->base + (reg))110#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))111 112#define ASB_BRDG_VERSION                0x00113#define ASB_CPR_CTRL                    0x04114 115#define ASB_V3D_S_CTRL			0x08116#define ASB_V3D_M_CTRL			0x0c117#define ASB_ISP_S_CTRL			0x10118#define ASB_ISP_M_CTRL			0x14119#define ASB_H264_S_CTRL			0x18120#define ASB_H264_M_CTRL			0x1c121 122#define ASB_REQ_STOP                    BIT(0)123#define ASB_ACK                         BIT(1)124#define ASB_EMPTY                       BIT(2)125#define ASB_FULL                        BIT(3)126 127#define ASB_AXI_BRDG_ID			0x20128 129#define BCM2835_BRDG_ID			0x62726467130 131struct bcm2835_power_domain {132	struct generic_pm_domain base;133	struct bcm2835_power *power;134	u32 domain;135	struct clk *clk;136};137 138struct bcm2835_power {139	struct device		*dev;140	/* PM registers. */141	void __iomem		*base;142	/* AXI Async bridge registers. */143	void __iomem		*asb;144	/* RPiVid bridge registers. */145	void __iomem		*rpivid_asb;146 147	struct genpd_onecell_data pd_xlate;148	struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];149	struct reset_controller_dev reset;150};151 152static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)153{154	void __iomem *base = power->asb;155	u64 start;156	u32 val;157 158	switch (reg) {159	case 0:160		return 0;161	case ASB_V3D_S_CTRL:162	case ASB_V3D_M_CTRL:163		if (power->rpivid_asb)164			base = power->rpivid_asb;165		break;166	}167 168	start = ktime_get_ns();169 170	/* Enable the module's async AXI bridges. */171	if (enable) {172		val = readl(base + reg) & ~ASB_REQ_STOP;173	} else {174		val = readl(base + reg) | ASB_REQ_STOP;175	}176	writel(PM_PASSWORD | val, base + reg);177 178	while (!!(readl(base + reg) & ASB_ACK) == enable) {179		cpu_relax();180		if (ktime_get_ns() - start >= 1000)181			return -ETIMEDOUT;182	}183 184	return 0;185}186 187static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)188{189	return bcm2835_asb_control(power, reg, true);190}191 192static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)193{194	return bcm2835_asb_control(power, reg, false);195}196 197static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)198{199	struct bcm2835_power *power = pd->power;200 201	/* We don't run this on BCM2711 */202	if (power->rpivid_asb)203		return 0;204 205	/* Enable functional isolation */206	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);207 208	/* Enable electrical isolation */209	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);210 211	/* Open the power switches. */212	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);213 214	return 0;215}216 217static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)218{219	struct bcm2835_power *power = pd->power;220	struct device *dev = power->dev;221	u64 start;222	int ret;223	int inrush;224	bool powok;225 226	/* We don't run this on BCM2711 */227	if (power->rpivid_asb)228		return 0;229 230	/* If it was already powered on by the fw, leave it that way. */231	if (PM_READ(pm_reg) & PM_POWUP)232		return 0;233 234	/* Enable power.  Allowing too much current at once may result235	 * in POWOK never getting set, so start low and ramp it up as236	 * necessary to succeed.237	 */238	powok = false;239	for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {240		PM_WRITE(pm_reg,241			 (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |242			 (inrush << PM_INRUSH_SHIFT) |243			 PM_POWUP);244 245		start = ktime_get_ns();246		while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {247			cpu_relax();248			if (ktime_get_ns() - start >= 3000)249				break;250		}251	}252	if (!powok) {253		dev_err(dev, "Timeout waiting for %s power OK\n",254			pd->base.name);255		ret = -ETIMEDOUT;256		goto err_disable_powup;257	}258 259	/* Disable electrical isolation */260	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);261 262	/* Repair memory */263	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);264	start = ktime_get_ns();265	while (!(PM_READ(pm_reg) & PM_MRDONE)) {266		cpu_relax();267		if (ktime_get_ns() - start >= 1000) {268			dev_err(dev, "Timeout waiting for %s memory repair\n",269				pd->base.name);270			ret = -ETIMEDOUT;271			goto err_disable_ispow;272		}273	}274 275	/* Disable functional isolation */276	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);277 278	return 0;279 280err_disable_ispow:281	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);282err_disable_powup:283	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));284	return ret;285}286 287static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,288				u32 pm_reg,289				u32 asb_m_reg,290				u32 asb_s_reg,291				u32 reset_flags)292{293	struct bcm2835_power *power = pd->power;294	int ret;295 296	ret = clk_prepare_enable(pd->clk);297	if (ret) {298		dev_err(power->dev, "Failed to enable clock for %s\n",299			pd->base.name);300		return ret;301	}302 303	/* Wait 32 clocks for reset to propagate, 1 us will be enough */304	udelay(1);305 306	clk_disable_unprepare(pd->clk);307 308	/* Deassert the resets. */309	PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);310 311	ret = clk_prepare_enable(pd->clk);312	if (ret) {313		dev_err(power->dev, "Failed to enable clock for %s\n",314			pd->base.name);315		goto err_enable_resets;316	}317 318	ret = bcm2835_asb_enable(power, asb_m_reg);319	if (ret) {320		dev_err(power->dev, "Failed to enable ASB master for %s\n",321			pd->base.name);322		goto err_disable_clk;323	}324	ret = bcm2835_asb_enable(power, asb_s_reg);325	if (ret) {326		dev_err(power->dev, "Failed to enable ASB slave for %s\n",327			pd->base.name);328		goto err_disable_asb_master;329	}330 331	return 0;332 333err_disable_asb_master:334	bcm2835_asb_disable(power, asb_m_reg);335err_disable_clk:336	clk_disable_unprepare(pd->clk);337err_enable_resets:338	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);339	return ret;340}341 342static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,343				 u32 pm_reg,344				 u32 asb_m_reg,345				 u32 asb_s_reg,346				 u32 reset_flags)347{348	struct bcm2835_power *power = pd->power;349	int ret;350 351	ret = bcm2835_asb_disable(power, asb_s_reg);352	if (ret) {353		dev_warn(power->dev, "Failed to disable ASB slave for %s\n",354			 pd->base.name);355		return ret;356	}357	ret = bcm2835_asb_disable(power, asb_m_reg);358	if (ret) {359		dev_warn(power->dev, "Failed to disable ASB master for %s\n",360			 pd->base.name);361		bcm2835_asb_enable(power, asb_s_reg);362		return ret;363	}364 365	clk_disable_unprepare(pd->clk);366 367	/* Assert the resets. */368	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);369 370	return 0;371}372 373static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)374{375	struct bcm2835_power_domain *pd =376		container_of(domain, struct bcm2835_power_domain, base);377	struct bcm2835_power *power = pd->power;378 379	switch (pd->domain) {380	case BCM2835_POWER_DOMAIN_GRAFX:381		return bcm2835_power_power_on(pd, PM_GRAFX);382 383	case BCM2835_POWER_DOMAIN_GRAFX_V3D:384		return bcm2835_asb_power_on(pd, PM_GRAFX,385					    ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,386					    PM_V3DRSTN);387 388	case BCM2835_POWER_DOMAIN_IMAGE:389		return bcm2835_power_power_on(pd, PM_IMAGE);390 391	case BCM2835_POWER_DOMAIN_IMAGE_PERI:392		return bcm2835_asb_power_on(pd, PM_IMAGE,393					    0, 0,394					    PM_PERIRSTN);395 396	case BCM2835_POWER_DOMAIN_IMAGE_ISP:397		return bcm2835_asb_power_on(pd, PM_IMAGE,398					    ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,399					    PM_ISPRSTN);400 401	case BCM2835_POWER_DOMAIN_IMAGE_H264:402		return bcm2835_asb_power_on(pd, PM_IMAGE,403					    ASB_H264_M_CTRL, ASB_H264_S_CTRL,404					    PM_H264RSTN);405 406	case BCM2835_POWER_DOMAIN_USB:407		PM_WRITE(PM_USB, PM_USB_CTRLEN);408		return 0;409 410	case BCM2835_POWER_DOMAIN_DSI0:411		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);412		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);413		return 0;414 415	case BCM2835_POWER_DOMAIN_DSI1:416		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);417		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);418		return 0;419 420	case BCM2835_POWER_DOMAIN_CCP2TX:421		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);422		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);423		return 0;424 425	case BCM2835_POWER_DOMAIN_HDMI:426		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);427		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);428		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);429		usleep_range(100, 200);430		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);431		return 0;432 433	default:434		dev_err(power->dev, "Invalid domain %d\n", pd->domain);435		return -EINVAL;436	}437}438 439static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)440{441	struct bcm2835_power_domain *pd =442		container_of(domain, struct bcm2835_power_domain, base);443	struct bcm2835_power *power = pd->power;444 445	switch (pd->domain) {446	case BCM2835_POWER_DOMAIN_GRAFX:447		return bcm2835_power_power_off(pd, PM_GRAFX);448 449	case BCM2835_POWER_DOMAIN_GRAFX_V3D:450		return bcm2835_asb_power_off(pd, PM_GRAFX,451					     ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,452					     PM_V3DRSTN);453 454	case BCM2835_POWER_DOMAIN_IMAGE:455		return bcm2835_power_power_off(pd, PM_IMAGE);456 457	case BCM2835_POWER_DOMAIN_IMAGE_PERI:458		return bcm2835_asb_power_off(pd, PM_IMAGE,459					     0, 0,460					     PM_PERIRSTN);461 462	case BCM2835_POWER_DOMAIN_IMAGE_ISP:463		return bcm2835_asb_power_off(pd, PM_IMAGE,464					     ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,465					     PM_ISPRSTN);466 467	case BCM2835_POWER_DOMAIN_IMAGE_H264:468		return bcm2835_asb_power_off(pd, PM_IMAGE,469					     ASB_H264_M_CTRL, ASB_H264_S_CTRL,470					     PM_H264RSTN);471 472	case BCM2835_POWER_DOMAIN_USB:473		PM_WRITE(PM_USB, 0);474		return 0;475 476	case BCM2835_POWER_DOMAIN_DSI0:477		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);478		PM_WRITE(PM_DSI0, 0);479		return 0;480 481	case BCM2835_POWER_DOMAIN_DSI1:482		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);483		PM_WRITE(PM_DSI1, 0);484		return 0;485 486	case BCM2835_POWER_DOMAIN_CCP2TX:487		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);488		PM_WRITE(PM_CCP2TX, 0);489		return 0;490 491	case BCM2835_POWER_DOMAIN_HDMI:492		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);493		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);494		return 0;495 496	default:497		dev_err(power->dev, "Invalid domain %d\n", pd->domain);498		return -EINVAL;499	}500}501 502static int503bcm2835_init_power_domain(struct bcm2835_power *power,504			  int pd_xlate_index, const char *name)505{506	struct device *dev = power->dev;507	struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];508 509	dom->clk = devm_clk_get(dev->parent, name);510	if (IS_ERR(dom->clk)) {511		int ret = PTR_ERR(dom->clk);512 513		if (ret == -EPROBE_DEFER)514			return ret;515 516		/* Some domains don't have a clk, so make sure that we517		 * don't deref an error pointer later.518		 */519		dom->clk = NULL;520	}521 522	dom->base.name = name;523	dom->base.power_on = bcm2835_power_pd_power_on;524	dom->base.power_off = bcm2835_power_pd_power_off;525 526	dom->domain = pd_xlate_index;527	dom->power = power;528 529	/* XXX: on/off at boot? */530	pm_genpd_init(&dom->base, NULL, true);531 532	power->pd_xlate.domains[pd_xlate_index] = &dom->base;533 534	return 0;535}536 537/** bcm2835_reset_reset - Resets a block that has a reset line in the538 * PM block.539 *540 * The consumer of the reset controller must have the power domain up541 * -- there's no reset ability with the power domain down.  To reset542 * the sub-block, we just disable its access to memory through the543 * ASB, reset, and re-enable.544 */545static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,546			       unsigned long id)547{548	struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,549						   reset);550	struct bcm2835_power_domain *pd;551	int ret;552 553	switch (id) {554	case BCM2835_RESET_V3D:555		pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];556		break;557	case BCM2835_RESET_H264:558		pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];559		break;560	case BCM2835_RESET_ISP:561		pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];562		break;563	default:564		dev_err(power->dev, "Bad reset id %ld\n", id);565		return -EINVAL;566	}567 568	ret = bcm2835_power_pd_power_off(&pd->base);569	if (ret)570		return ret;571 572	return bcm2835_power_pd_power_on(&pd->base);573}574 575static int bcm2835_reset_status(struct reset_controller_dev *rcdev,576				unsigned long id)577{578	struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,579						   reset);580 581	switch (id) {582	case BCM2835_RESET_V3D:583		return !PM_READ(PM_GRAFX & PM_V3DRSTN);584	case BCM2835_RESET_H264:585		return !PM_READ(PM_IMAGE & PM_H264RSTN);586	case BCM2835_RESET_ISP:587		return !PM_READ(PM_IMAGE & PM_ISPRSTN);588	default:589		return -EINVAL;590	}591}592 593static const struct reset_control_ops bcm2835_reset_ops = {594	.reset = bcm2835_reset_reset,595	.status = bcm2835_reset_status,596};597 598static const char *const power_domain_names[] = {599	[BCM2835_POWER_DOMAIN_GRAFX] = "grafx",600	[BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",601 602	[BCM2835_POWER_DOMAIN_IMAGE] = "image",603	[BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",604	[BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",605	[BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",606 607	[BCM2835_POWER_DOMAIN_USB] = "usb",608	[BCM2835_POWER_DOMAIN_DSI0] = "dsi0",609	[BCM2835_POWER_DOMAIN_DSI1] = "dsi1",610	[BCM2835_POWER_DOMAIN_CAM0] = "cam0",611	[BCM2835_POWER_DOMAIN_CAM1] = "cam1",612	[BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",613	[BCM2835_POWER_DOMAIN_HDMI] = "hdmi",614};615 616static int bcm2835_power_probe(struct platform_device *pdev)617{618	struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);619	struct device *dev = &pdev->dev;620	struct bcm2835_power *power;621	static const struct {622		int parent, child;623	} domain_deps[] = {624		{ BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },625		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },626		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },627		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },628		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },629		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },630		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },631	};632	int ret = 0, i;633	u32 id;634 635	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);636	if (!power)637		return -ENOMEM;638	platform_set_drvdata(pdev, power);639 640	power->dev = dev;641	power->base = pm->base;642	power->asb = pm->asb;643	power->rpivid_asb = pm->rpivid_asb;644 645	id = readl(power->asb + ASB_AXI_BRDG_ID);646	if (id != BCM2835_BRDG_ID /* "BRDG" */) {647		dev_err(dev, "ASB register ID returned 0x%08x\n", id);648		return -ENODEV;649	}650 651	if (power->rpivid_asb) {652		id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);653		if (id != BCM2835_BRDG_ID /* "BRDG" */) {654			dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",655				     id);656			return -ENODEV;657		}658	}659 660	power->pd_xlate.domains = devm_kcalloc(dev,661					       ARRAY_SIZE(power_domain_names),662					       sizeof(*power->pd_xlate.domains),663					       GFP_KERNEL);664	if (!power->pd_xlate.domains)665		return -ENOMEM;666 667	power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);668 669	for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {670		ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);671		if (ret)672			goto fail;673	}674 675	for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {676		pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,677				       &power->domains[domain_deps[i].child].base);678	}679 680	power->reset.owner = THIS_MODULE;681	power->reset.nr_resets = BCM2835_RESET_COUNT;682	power->reset.ops = &bcm2835_reset_ops;683	power->reset.of_node = dev->parent->of_node;684 685	ret = devm_reset_controller_register(dev, &power->reset);686	if (ret)687		goto fail;688 689	of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);690 691	dev_info(dev, "Broadcom BCM2835 power domains driver");692	return 0;693 694fail:695	for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {696		struct generic_pm_domain *dom = &power->domains[i].base;697 698		if (dom->name)699			pm_genpd_remove(dom);700	}701	return ret;702}703 704static struct platform_driver bcm2835_power_driver = {705	.probe		= bcm2835_power_probe,706	.driver = {707		.name =	"bcm2835-power",708	},709};710module_platform_driver(bcm2835_power_driver);711 712MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");713MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");714