iommu: arm-smmu: Abstract power resources from struct arm_smmu_device

Directly containing clock and regulator structures within struct
arm_smmu_device forces the functions which enable/disable/initialize clocks
and regulators to use struct arm_smmu_device. This prevents code reuse.
Future changes will use a second struct which also needs to control clocks
and regulators.

Change-Id: I978d80d25217b8f4d560f02c68e84d3f2da50b2c
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 5417b7e..9076451 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -343,6 +343,33 @@
 	struct arm_smmu_master_cfg	cfg;
 };
 
+/*
+ * Describes resources required for on/off power operation.
+ * Separate reference count is provided for atomic/nonatomic
+ * operations.
+ */
+struct arm_smmu_power_resources {
+	struct platform_device		*pdev;
+	struct device			*dev;
+
+	struct clk			**clocks;
+	int				num_clocks;
+
+	struct regulator_bulk_data	*gdscs;
+	int				num_gdscs;
+
+	uint32_t			bus_client;
+	struct msm_bus_scale_pdata	*bus_dt_data;
+
+	/* Protects power_count */
+	struct mutex			power_lock;
+	int				power_count;
+
+	/* Protects clock_refs_count */
+	spinlock_t			clock_refs_lock;
+	int				clock_refs_count;
+};
+
 struct arm_smmu_device {
 	struct device			*dev;
 
@@ -397,20 +424,7 @@
 	struct arm_smmu_impl_def_reg	*impl_def_attach_registers;
 	unsigned int			num_impl_def_attach_registers;
 
-	int				num_clocks;
-	struct clk			**clocks;
-
-	struct regulator		*gdsc;
-
-	uint32_t			bus_client;
-	struct msm_bus_scale_pdata	*bus_dt_data;
-
-	/* Protects power_count */
-	struct mutex			power_lock;
-	int				power_count;
-	/* Protects clock_refs_count */
-	spinlock_t			clock_refs_lock;
-	int				clock_refs_count;
+	struct arm_smmu_power_resources *pwr;
 
 	spinlock_t			atos_lock;
 
@@ -786,188 +800,193 @@
 	clear_bit(idx, map);
 }
 
-static int arm_smmu_prepare_clocks(struct arm_smmu_device *smmu)
+static int arm_smmu_prepare_clocks(struct arm_smmu_power_resources *pwr)
 {
 	int i, ret = 0;
 
-	for (i = 0; i < smmu->num_clocks; ++i) {
-		ret = clk_prepare(smmu->clocks[i]);
+	for (i = 0; i < pwr->num_clocks; ++i) {
+		ret = clk_prepare(pwr->clocks[i]);
 		if (ret) {
-			dev_err(smmu->dev, "Couldn't prepare clock #%d\n", i);
+			dev_err(pwr->dev, "Couldn't prepare clock #%d\n", i);
 			while (i--)
-				clk_unprepare(smmu->clocks[i]);
+				clk_unprepare(pwr->clocks[i]);
 			break;
 		}
 	}
 	return ret;
 }
 
-static void arm_smmu_unprepare_clocks(struct arm_smmu_device *smmu)
+static void arm_smmu_unprepare_clocks(struct arm_smmu_power_resources *pwr)
 {
 	int i;
 
-	for (i = smmu->num_clocks; i; --i)
-		clk_unprepare(smmu->clocks[i - 1]);
+	for (i = pwr->num_clocks; i; --i)
+		clk_unprepare(pwr->clocks[i - 1]);
 }
 
-/* Clocks must be prepared before this (arm_smmu_prepare_clocks) */
-static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu)
+static int arm_smmu_enable_clocks(struct arm_smmu_power_resources *pwr)
 {
 	int i, ret = 0;
-	unsigned long flags;
 
-	spin_lock_irqsave(&smmu->clock_refs_lock, flags);
-	if (smmu->clock_refs_count > 0) {
-		smmu->clock_refs_count++;
-		spin_unlock_irqrestore(&smmu->clock_refs_lock, flags);
-		return 0;
-	}
-
-	for (i = 0; i < smmu->num_clocks; ++i) {
-		ret = clk_enable(smmu->clocks[i]);
+	for (i = 0; i < pwr->num_clocks; ++i) {
+		ret = clk_enable(pwr->clocks[i]);
 		if (ret) {
-			dev_err(smmu->dev, "Couldn't enable clock #%d\n", i);
+			dev_err(pwr->dev, "Couldn't enable clock #%d\n", i);
 			while (i--)
-				clk_disable(smmu->clocks[i]);
+				clk_disable(pwr->clocks[i]);
 			break;
 		}
 	}
 
-	if (!ret)
-		smmu->clock_refs_count++;
+	return ret;
+}
 
-	spin_unlock_irqrestore(&smmu->clock_refs_lock, flags);
+static void arm_smmu_disable_clocks(struct arm_smmu_power_resources *pwr)
+{
+	int i;
+
+	for (i = pwr->num_clocks; i; --i)
+		clk_disable(pwr->clocks[i - 1]);
+}
+
+static int arm_smmu_request_bus(struct arm_smmu_power_resources *pwr)
+{
+	if (!pwr->bus_client)
+		return 0;
+	return msm_bus_scale_client_update_request(pwr->bus_client, 1);
+}
+
+static void arm_smmu_unrequest_bus(struct arm_smmu_power_resources *pwr)
+{
+	if (!pwr->bus_client)
+		return;
+	WARN_ON(msm_bus_scale_client_update_request(pwr->bus_client, 0));
+}
+
+/* Clocks must be prepared before this (arm_smmu_prepare_clocks) */
+static int arm_smmu_power_on_atomic(struct arm_smmu_power_resources *pwr)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pwr->clock_refs_lock, flags);
+	if (pwr->clock_refs_count > 0) {
+		pwr->clock_refs_count++;
+		spin_unlock_irqrestore(&pwr->clock_refs_lock, flags);
+		return 0;
+	}
+
+	ret = arm_smmu_enable_clocks(pwr);
+	if (!ret)
+		pwr->clock_refs_count = 1;
+
+	spin_unlock_irqrestore(&pwr->clock_refs_lock, flags);
 	return ret;
 }
 
 /* Clocks should be unprepared after this (arm_smmu_unprepare_clocks) */
-static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu)
+static void arm_smmu_power_off_atomic(struct arm_smmu_power_resources *pwr)
 {
-	int i;
 	unsigned long flags;
 
-	spin_lock_irqsave(&smmu->clock_refs_lock, flags);
-	WARN_ON(smmu->clock_refs_count == 0);
-	if (smmu->clock_refs_count > 1) {
-		smmu->clock_refs_count--;
-		spin_unlock_irqrestore(&smmu->clock_refs_lock, flags);
+	spin_lock_irqsave(&pwr->clock_refs_lock, flags);
+	if (pwr->clock_refs_count == 0) {
+		WARN(1, "%s: bad clock_ref_count\n", dev_name(pwr->dev));
+		spin_unlock_irqrestore(&pwr->clock_refs_lock, flags);
+		return;
+
+	} else if (pwr->clock_refs_count > 1) {
+		pwr->clock_refs_count--;
+		spin_unlock_irqrestore(&pwr->clock_refs_lock, flags);
 		return;
 	}
 
-	for (i = smmu->num_clocks; i; --i)
-		clk_disable(smmu->clocks[i - 1]);
+	arm_smmu_disable_clocks(pwr);
 
-	smmu->clock_refs_count--;
-	spin_unlock_irqrestore(&smmu->clock_refs_lock, flags);
+	pwr->clock_refs_count = 0;
+	spin_unlock_irqrestore(&pwr->clock_refs_lock, flags);
 }
 
-static int arm_smmu_enable_regulators(struct arm_smmu_device *smmu)
-{
-	if (!smmu->gdsc)
-		return 0;
-
-	return regulator_enable(smmu->gdsc);
-}
-
-static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu)
-{
-	if (!smmu->gdsc)
-		return 0;
-
-	return regulator_disable(smmu->gdsc);
-}
-
-static int arm_smmu_request_bus(uint32_t client)
-{
-	if (!client)
-		return 0;
-	return msm_bus_scale_client_update_request(client, 1);
-}
-
-static void arm_smmu_unrequest_bus(uint32_t client)
-{
-	if (!client)
-		return;
-	WARN_ON(msm_bus_scale_client_update_request(client, 0));
-}
-
-static int arm_smmu_power_on_slow(struct arm_smmu_device *smmu)
+static int arm_smmu_power_on_slow(struct arm_smmu_power_resources *pwr)
 {
 	int ret;
 
-	mutex_lock(&smmu->power_lock);
-	if (smmu->power_count > 0) {
-		smmu->power_count += 1;
-		mutex_unlock(&smmu->power_lock);
+	mutex_lock(&pwr->power_lock);
+	if (pwr->power_count > 0) {
+		pwr->power_count += 1;
+		mutex_unlock(&pwr->power_lock);
 		return 0;
 	}
 
-	ret = arm_smmu_enable_regulators(smmu);
+	ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
 	if (ret)
 		goto out_unlock;
 
-	ret = arm_smmu_request_bus(smmu->bus_client);
+	ret = arm_smmu_request_bus(pwr);
 	if (ret)
 		goto out_disable_regulators;
 
-	ret = arm_smmu_prepare_clocks(smmu);
+	ret = arm_smmu_prepare_clocks(pwr);
 	if (ret)
 		goto out_disable_bus;
 
-	smmu->power_count += 1;
-	mutex_unlock(&smmu->power_lock);
+	pwr->power_count = 1;
+	mutex_unlock(&pwr->power_lock);
 	return 0;
 
 out_disable_bus:
-	arm_smmu_unrequest_bus(smmu->bus_client);
+	arm_smmu_unrequest_bus(pwr);
 out_disable_regulators:
-	arm_smmu_disable_regulators(smmu);
+	regulator_bulk_disable(pwr->num_gdscs, pwr->gdscs);
 out_unlock:
-	mutex_unlock(&smmu->power_lock);
+	mutex_unlock(&pwr->power_lock);
 	return ret;
 }
 
-static void arm_smmu_power_off_slow(struct arm_smmu_device *smmu)
+static void arm_smmu_power_off_slow(struct arm_smmu_power_resources *pwr)
 {
-	mutex_lock(&smmu->power_lock);
-	smmu->power_count--;
-	WARN_ON(smmu->power_count < 0);
+	mutex_lock(&pwr->power_lock);
+	if (pwr->power_count == 0) {
+		WARN(1, "%s: Bad power count\n", dev_name(pwr->dev));
+		mutex_unlock(&pwr->power_lock);
+		return;
 
-	if (smmu->power_count > 0) {
-		mutex_unlock(&smmu->power_lock);
+	} else if (pwr->power_count > 1) {
+		pwr->power_count--;
+		mutex_unlock(&pwr->power_lock);
 		return;
 	}
 
-	arm_smmu_unprepare_clocks(smmu);
-	arm_smmu_unrequest_bus(smmu->bus_client);
-	arm_smmu_disable_regulators(smmu);
+	arm_smmu_unprepare_clocks(pwr);
+	arm_smmu_unrequest_bus(pwr);
+	regulator_bulk_disable(pwr->num_gdscs, pwr->gdscs);
 
-	mutex_unlock(&smmu->power_lock);
+	mutex_unlock(&pwr->power_lock);
 }
 
-static int arm_smmu_power_on(struct arm_smmu_device *smmu)
+static int arm_smmu_power_on(struct arm_smmu_power_resources *pwr)
 {
 	int ret;
 
-	ret = arm_smmu_power_on_slow(smmu);
+	ret = arm_smmu_power_on_slow(pwr);
 	if (ret)
 		return ret;
 
-	ret = arm_smmu_enable_clocks_atomic(smmu);
+	ret = arm_smmu_power_on_atomic(pwr);
 	if (ret)
 		goto out_disable;
 
 	return 0;
 
 out_disable:
-	arm_smmu_power_off_slow(smmu);
+	arm_smmu_power_off_slow(pwr);
 	return ret;
 }
 
-static void arm_smmu_power_off(struct arm_smmu_device *smmu)
+static void arm_smmu_power_off(struct arm_smmu_power_resources *pwr)
 {
-	arm_smmu_disable_clocks_atomic(smmu);
-	arm_smmu_power_off_slow(smmu);
+	arm_smmu_power_off_atomic(pwr);
+	arm_smmu_power_off_slow(pwr);
 }
 
 /*
@@ -981,9 +1000,9 @@
 	int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);
 
 	if (atomic_domain)
-		return arm_smmu_enable_clocks_atomic(smmu);
+		return arm_smmu_power_on_atomic(smmu->pwr);
 
-	return arm_smmu_power_on(smmu);
+	return arm_smmu_power_on(smmu->pwr);
 }
 
 /*
@@ -997,11 +1016,11 @@
 	int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);
 
 	if (atomic_domain) {
-		arm_smmu_disable_clocks_atomic(smmu);
+		arm_smmu_power_off_atomic(smmu->pwr);
 		return;
 	}
 
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 }
 
 /* Wait for any pending TLB invalidations to complete */
@@ -1259,7 +1278,7 @@
 				      DEFAULT_RATELIMIT_INTERVAL,
 				      DEFAULT_RATELIMIT_BURST);
 
-	ret = arm_smmu_power_on(smmu);
+	ret = arm_smmu_power_on(smmu->pwr);
 	if (ret)
 		return IRQ_NONE;
 
@@ -1372,7 +1391,7 @@
 	}
 
 out_power_off:
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 
 	return ret;
 }
@@ -1383,7 +1402,7 @@
 	struct arm_smmu_device *smmu = dev;
 	void __iomem *gr0_base = ARM_SMMU_GR0_NS(smmu);
 
-	if (arm_smmu_power_on(smmu))
+	if (arm_smmu_power_on(smmu->pwr))
 		return IRQ_NONE;
 
 	gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
@@ -1392,7 +1411,7 @@
 	gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
 
 	if (!gfsr) {
-		arm_smmu_power_off(smmu);
+		arm_smmu_power_off(smmu->pwr);
 		return IRQ_NONE;
 	}
 
@@ -1403,7 +1422,7 @@
 		gfsr, gfsynr0, gfsynr1, gfsynr2);
 
 	writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 	return IRQ_HANDLED;
 }
 
@@ -1757,7 +1776,7 @@
 	if (!smmu || domain->type == IOMMU_DOMAIN_DMA)
 		return;
 
-	ret = arm_smmu_power_on(smmu);
+	ret = arm_smmu_power_on(smmu->pwr);
 	if (ret) {
 		WARN_ONCE(ret, "Woops, powering on smmu %p failed. Leaking context bank\n",
 				smmu);
@@ -1768,7 +1787,7 @@
 	if (dynamic) {
 		arm_smmu_free_asid(domain);
 		free_io_pgtable_ops(smmu_domain->pgtbl_ops);
-		arm_smmu_power_off(smmu);
+		arm_smmu_power_off(smmu->pwr);
 		arm_smmu_secure_domain_lock(smmu_domain);
 		arm_smmu_secure_pool_destroy(smmu_domain);
 		arm_smmu_unassign_table(smmu_domain);
@@ -1795,7 +1814,7 @@
 	arm_smmu_secure_domain_unlock(smmu_domain);
 	__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
 
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 }
 
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
@@ -2004,8 +2023,8 @@
 
 	/* Remove additional vote for atomic power */
 	if (atomic_domain) {
-		WARN_ON(arm_smmu_enable_clocks_atomic(smmu));
-		arm_smmu_power_off(smmu);
+		WARN_ON(arm_smmu_power_on_atomic(smmu->pwr));
+		arm_smmu_power_off(smmu->pwr);
 	}
 }
 
@@ -2109,7 +2128,7 @@
 	}
 
 	/* Enable Clocks and Power */
-	ret = arm_smmu_power_on(smmu);
+	ret = arm_smmu_power_on(smmu->pwr);
 	if (ret)
 		return ret;
 
@@ -2118,11 +2137,11 @@
 	 * detached
 	 */
 	if (atomic_domain) {
-		ret = arm_smmu_power_on(smmu);
+		ret = arm_smmu_power_on(smmu->pwr);
 		if (ret)
 			goto out_power_off;
 
-		arm_smmu_disable_clocks_atomic(smmu);
+		arm_smmu_power_off_atomic(smmu->pwr);
 	}
 
 	/* Ensure that the domain is finalised */
@@ -2164,7 +2183,7 @@
 		dev->archdata.iommu = domain;
 
 out_power_off:
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 
 	return ret;
 }
@@ -2703,7 +2722,7 @@
 	}
 
 	smmu = smmu_domain->smmu;
-	if (arm_smmu_power_on(smmu))
+	if (arm_smmu_power_on(smmu->pwr))
 		return;
 
 	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
@@ -2713,7 +2732,7 @@
 	/* give the interrupt time to fire... */
 	msleep(1000);
 
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 }
 
 static unsigned long arm_smmu_reg_read(struct iommu_domain *domain,
@@ -2737,13 +2756,13 @@
 		return val;
 	}
 
-	if (arm_smmu_power_on(smmu))
+	if (arm_smmu_power_on(smmu->pwr))
 		return 0;
 
 	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
 	val = readl_relaxed(cb_base + offset);
 
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 	return val;
 }
 
@@ -2766,13 +2785,13 @@
 		return;
 	}
 
-	if (arm_smmu_power_on(smmu))
+	if (arm_smmu_power_on(smmu->pwr))
 		return;
 
 	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
 	writel_relaxed(val, cb_base + offset);
 
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 }
 
 static void arm_smmu_tlbi_domain(struct iommu_domain *domain)
@@ -2784,14 +2803,14 @@
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
-	return arm_smmu_power_on(smmu_domain->smmu);
+	return arm_smmu_power_on(smmu_domain->smmu->pwr);
 }
 
 static void arm_smmu_disable_config_clocks(struct iommu_domain *domain)
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
-	arm_smmu_power_off(smmu_domain->smmu);
+	arm_smmu_power_off(smmu_domain->smmu->pwr);
 }
 
 static struct iommu_ops arm_smmu_ops = {
@@ -2916,7 +2935,7 @@
 	phys_addr_t phys = 0;
 	unsigned long flags;
 
-	ret = arm_smmu_power_on(smmu_domain->smmu);
+	ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
 	if (ret)
 		return 0;
 
@@ -2936,7 +2955,7 @@
 		qsmmuv2_resume(smmu);
 
 out_power_off:
-	arm_smmu_power_off(smmu_domain->smmu);
+	arm_smmu_power_off(smmu_domain->smmu->pwr);
 	return phys;
 }
 
@@ -3154,30 +3173,28 @@
 	return 0;
 }
 
-static int arm_smmu_init_clocks(struct arm_smmu_device *smmu)
+
+static int arm_smmu_init_clocks(struct arm_smmu_power_resources *pwr)
 {
 	const char *cname;
 	struct property *prop;
 	int i;
-	struct device *dev = smmu->dev;
+	struct device *dev = pwr->dev;
 
-	smmu->num_clocks =
+	pwr->num_clocks =
 		of_property_count_strings(dev->of_node, "clock-names");
 
-	if (smmu->num_clocks < 1) {
-		smmu->num_clocks = 0;
+	if (pwr->num_clocks < 1) {
+		pwr->num_clocks = 0;
 		return 0;
 	}
 
-	smmu->clocks = devm_kzalloc(
-		dev, sizeof(*smmu->clocks) * smmu->num_clocks,
+	pwr->clocks = devm_kzalloc(
+		dev, sizeof(*pwr->clocks) * pwr->num_clocks,
 		GFP_KERNEL);
 
-	if (!smmu->clocks) {
-		dev_err(dev,
-			"Failed to allocate memory for clocks\n");
-		return -ENODEV;
-	}
+	if (!pwr->clocks)
+		return -ENOMEM;
 
 	i = 0;
 	of_property_for_each_string(dev->of_node, "clock-names",
@@ -3196,63 +3213,109 @@
 			clk_set_rate(c, rate);
 		}
 
-		smmu->clocks[i] = c;
+		pwr->clocks[i] = c;
 
 		++i;
 	}
 	return 0;
 }
 
-static int arm_smmu_init_regulators(struct arm_smmu_device *smmu)
+static int arm_smmu_init_regulators(struct arm_smmu_power_resources *pwr)
 {
-	struct device *dev = smmu->dev;
+	const char *cname;
+	struct property *prop;
+	int i, ret = 0;
+	struct device *dev = pwr->dev;
 
-	if (!of_get_property(dev->of_node, "vdd-supply", NULL))
+	pwr->num_gdscs =
+		of_property_count_strings(dev->of_node, "qcom,regulator-names");
+
+	if (pwr->num_gdscs < 1) {
+		pwr->num_gdscs = 0;
 		return 0;
+	}
 
-	smmu->gdsc = devm_regulator_get(dev, "vdd");
-	if (IS_ERR(smmu->gdsc))
-		return PTR_ERR(smmu->gdsc);
+	pwr->gdscs = devm_kzalloc(
+			dev, sizeof(*pwr->gdscs) * pwr->num_gdscs, GFP_KERNEL);
+
+	if (!pwr->gdscs)
+		return -ENOMEM;
+
+	i = 0;
+	of_property_for_each_string(dev->of_node, "qcom,regulator-names",
+				prop, cname)
+		pwr->gdscs[i].supply = cname;
+
+	ret = devm_regulator_bulk_get(dev, pwr->num_gdscs, pwr->gdscs);
+	return ret;
+}
+
+static int arm_smmu_init_bus_scaling(struct arm_smmu_power_resources *pwr)
+{
+	struct device *dev = pwr->dev;
+
+	/* We don't want the bus APIs to print an error message */
+	if (!of_find_property(dev->of_node, "qcom,msm-bus,name", NULL)) {
+		dev_dbg(dev, "No bus scaling info\n");
+		return 0;
+	}
+
+	pwr->bus_dt_data = msm_bus_cl_get_pdata(pwr->pdev);
+	if (!pwr->bus_dt_data) {
+		dev_err(dev, "Unable to read bus-scaling from devicetree\n");
+		return -EINVAL;
+	}
+
+	pwr->bus_client = msm_bus_scale_register_client(pwr->bus_dt_data);
+	if (!pwr->bus_client) {
+		dev_err(dev, "Bus client registration failed\n");
+		msm_bus_cl_clear_pdata(pwr->bus_dt_data);
+		return -EINVAL;
+	}
 
 	return 0;
 }
 
-static int arm_smmu_init_bus_scaling(struct platform_device *pdev,
-				     uint32_t *client,
-				     struct msm_bus_scale_pdata **data)
+/*
+ * Cleanup done by devm. Any non-devm resources must clean up themselves.
+ */
+static struct arm_smmu_power_resources *arm_smmu_init_power_resources(
+						struct platform_device *pdev)
 {
-	uint32_t __client;
+	struct arm_smmu_power_resources *pwr;
+	int ret;
 
-	if (!of_find_property(pdev->dev.of_node, "qcom,msm-bus,name", NULL)) {
-		dev_dbg(&pdev->dev, "No bus scaling info\n");
-		return 0;
-	}
+	pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
+	if (!pwr)
+		return ERR_PTR(-ENOMEM);
 
-	*data = msm_bus_cl_get_pdata(pdev);
-	if (*data) {
-		dev_err(&pdev->dev, "Unable to read bus-scaling from devicetree\n");
-		return -EINVAL;
-	}
+	pwr->dev = &pdev->dev;
+	pwr->pdev = pdev;
+	mutex_init(&pwr->power_lock);
+	spin_lock_init(&pwr->clock_refs_lock);
 
-	__client = msm_bus_scale_register_client(*data);
-	if (!__client) {
-		dev_err(&pdev->dev, "Bus client registration failed\n");
-		msm_bus_cl_clear_pdata(*data);
-		return -EINVAL;
-	}
+	ret = arm_smmu_init_clocks(pwr);
+	if (ret)
+		return ERR_PTR(ret);
 
-	*client = __client;
-	return 0;
+	ret = arm_smmu_init_regulators(pwr);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = arm_smmu_init_bus_scaling(pwr);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return pwr;
 }
 
 /*
  * Bus APIs are not devm-safe.
  */
-static void arm_smmu_exit_bus_scaling(uint32_t *client,
-				      struct msm_bus_scale_pdata **data)
+static void arm_smmu_exit_power_resources(struct arm_smmu_power_resources *pwr)
 {
-	msm_bus_scale_unregister_client(*client);
-	msm_bus_cl_clear_pdata(*data);
+	msm_bus_scale_unregister_client(pwr->bus_client);
+	msm_bus_cl_clear_pdata(pwr->bus_dt_data);
 }
 
 static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
@@ -3526,8 +3589,6 @@
 	}
 	smmu->dev = dev;
 	spin_lock_init(&smmu->atos_lock);
-	mutex_init(&smmu->power_lock);
-	spin_lock_init(&smmu->clock_refs_lock);
 	idr_init(&smmu->asid_idr);
 	mutex_init(&smmu->idr_mutex);
 
@@ -3581,22 +3642,14 @@
 
 	parse_driver_options(smmu);
 
-	err = arm_smmu_init_clocks(smmu);
-	if (err)
-		return err;
 
-	err = arm_smmu_init_regulators(smmu);
-	if (err)
-		return err;
+	smmu->pwr = arm_smmu_init_power_resources(pdev);
+	if (IS_ERR(smmu->pwr))
+		return PTR_ERR(smmu->pwr);
 
-	err = arm_smmu_init_bus_scaling(pdev, &smmu->bus_client,
-					&smmu->bus_dt_data);
+	err = arm_smmu_power_on(smmu->pwr);
 	if (err)
-		return err;
-
-	err = arm_smmu_power_on(smmu);
-	if (err)
-		goto out_exit_bus;
+		goto out_exit_power_resources;
 
 	err = arm_smmu_device_cfg_probe(smmu);
 	if (err)
@@ -3646,7 +3699,7 @@
 		goto out_put_masters;
 
 	arm_smmu_device_reset(smmu);
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 
 	return 0;
 
@@ -3658,10 +3711,10 @@
 	}
 
 out_power_off:
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 
-out_exit_bus:
-	arm_smmu_exit_bus_scaling(&smmu->bus_client, &smmu->bus_dt_data);
+out_exit_power_resources:
+	arm_smmu_exit_power_resources(smmu->pwr);
 
 	return err;
 }
@@ -3686,7 +3739,7 @@
 	if (!smmu)
 		return -ENODEV;
 
-	if (arm_smmu_power_on(smmu))
+	if (arm_smmu_power_on(smmu->pwr))
 		return -EINVAL;
 
 	for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
@@ -3705,9 +3758,9 @@
 
 	/* Turn the thing off */
 	writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
-	arm_smmu_power_off(smmu);
+	arm_smmu_power_off(smmu->pwr);
 
-	arm_smmu_exit_bus_scaling(&smmu->bus_client, &smmu->bus_dt_data);
+	arm_smmu_exit_power_resources(smmu->pwr);
 
 	return 0;
 }