OPP: decouple dt properties in opp_parse_supplies()

Message ID 20221030034414.24672-1-jcalligeros99@gmail.com
State New
Headers
Series OPP: decouple dt properties in opp_parse_supplies() |

Commit Message

James Calligeros Oct. 30, 2022, 3:44 a.m. UTC
  The opp-microwatt property was added with the intention of providing
platforms a way to specify a precise value for the power consumption
of a device at a given OPP to enable better energy-aware scheduling
decisions by informing the kernel of the total static and dynamic
power of a device at a given OPP, removing the reliance on the EM
subsystem's often flawed estimations. This property is parsed by
opp_parse_supplies(), which creates a hard dependency on the
opp-microvolt property.

Some platforms, such as Apple Silicon, do not describe their devices'
voltage regulators in the DT as they cannot be controlled by the kernel
and/or rely on opaque firmware algorithms to control their voltage and
current characteristics at runtime. We can, however, experimentally
determine the power consumption of a given device at a given OPP, taking
advantage of opp-microwatt to provide EAS on such devices as was initially
intended.

Allow platforms to specify and consume any subset of opp-microvolt,
opp-microamp, or opp-microwatt without a hard dependency on opp-microvolt
to enable this functionality on such platforms.

Fixes: 4f9a7a1dc2a2 ("OPP: Add "opp-microwatt" supporting code")
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
 drivers/opp/of.c | 198 +++++++++++++++++++++++++----------------------
 1 file changed, 104 insertions(+), 94 deletions(-)
  

Comments

kernel test robot Oct. 30, 2022, 5:24 a.m. UTC | #1
Hi James,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.1-rc2 next-20221028]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/James-Calligeros/OPP-decouple-dt-properties-in-opp_parse_supplies/20221030-114618
patch link:    https://lore.kernel.org/r/20221030034414.24672-1-jcalligeros99%40gmail.com
patch subject: [PATCH] OPP: decouple dt properties in opp_parse_supplies()
config: arc-randconfig-r043-20221030
compiler: arceb-elf-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/c88dea73d372f38c7f3ab19f688cf210d49481ea
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review James-Calligeros/OPP-decouple-dt-properties-in-opp_parse_supplies/20221030-114618
        git checkout c88dea73d372f38c7f3ab19f688cf210d49481ea
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash drivers/opp/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/opp/of.c: In function 'opp_parse_supplies':
>> drivers/opp/of.c:739:20: error: 'struct dev_pm_opp' has no member named 'regulator_count'
     739 |                 opp->regulator_count = 0;
         |                    ^~

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for VIDEO_MEDIATEK_VPU
   Depends on [n]: MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && V4L_MEM2MEM_DRIVERS [=n] && VIDEO_DEV [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y])
   Selected by [y]:
   - VIDEO_MEDIATEK_MDP3 [=y] && MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && (MTK_IOMMU [=n] || COMPILE_TEST [=y]) && VIDEO_DEV [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && HAS_DMA [=y] && REMOTEPROC [=y]


vim +739 drivers/opp/of.c

   580	
   581	static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
   582				      struct opp_table *opp_table)
   583	{
   584		u32 *microvolt = NULL, *microamp = NULL, *microwatt = NULL;
   585		int supplies = opp_table->regulator_count;
   586		int vcount, icount, pcount, ret, i, j;
   587		struct property *prop_mv = NULL, *prop_ma = NULL, *prop_mw = NULL;
   588		char name[NAME_MAX];
   589	
   590		/* Search for "opp-microvolt-<name>" */
   591		if (opp_table->prop_name) {
   592			snprintf(name, sizeof(name), "opp-microvolt-%s",
   593				 opp_table->prop_name);
   594			prop_mv = of_find_property(opp->np, name, NULL);
   595		}
   596	
   597		if (!prop_mv) {
   598			/* Search for "opp-microvolt" */
   599			sprintf(name, "opp-microvolt");
   600			prop_mv = of_find_property(opp->np, name, NULL);
   601	
   602		}
   603	
   604		if (prop_mv) {
   605			vcount = of_property_count_u32_elems(opp->np, name);
   606			if (unlikely(supplies == -1))
   607				supplies = opp_table->regulator_count = vcount;
   608		} else {
   609			prop_mv = NULL;
   610			vcount = 0;
   611		}
   612	
   613		if (vcount < 0) {
   614			dev_err(dev, "%s: Invalid %s property (%d)\n",
   615				__func__, name, vcount);
   616			return vcount;
   617		}
   618	
   619		if (vcount) {
   620			/* There can be one or three elements per supply */
   621			if (vcount != supplies && vcount != supplies * 3) {
   622				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   623					__func__, name, vcount, supplies);
   624				return -EINVAL;
   625			}
   626	
   627			microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
   628			if (!microvolt)
   629				return -ENOMEM;
   630	
   631			ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
   632			if (ret) {
   633				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   634				ret = -EINVAL;
   635				goto free_microvolt;
   636			}
   637		}
   638	
   639		/* Search for "opp-microamp-<name>" */
   640		if (opp_table->prop_name) {
   641			snprintf(name, sizeof(name), "opp-microamp-%s",
   642				 opp_table->prop_name);
   643			prop_ma = of_find_property(opp->np, name, NULL);
   644		}
   645	
   646		if (!prop_ma) {
   647			/* Search for "opp-microamp" */
   648			sprintf(name, "opp-microamp");
   649			prop_ma = of_find_property(opp->np, name, NULL);
   650	
   651		}
   652	
   653		if (prop_ma) {
   654			icount = of_property_count_u32_elems(opp->np, name);
   655			if (unlikely(supplies == -1))
   656				supplies = opp_table->regulator_count = icount;
   657		} else {
   658			prop_ma = NULL;
   659			icount = 0;
   660		}
   661	
   662		if (icount < 0) {
   663			dev_err(dev, "%s: Invalid %s property (%d)\n",
   664				__func__, name, icount);
   665			return icount;
   666		}
   667	
   668		if (icount) {
   669			/* There can be one or three elements per supply */
   670			if (icount != supplies && icount != supplies * 3) {
   671				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   672					__func__, name, icount, supplies);
   673				return -EINVAL;
   674			}
   675	
   676			microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
   677			if (!microamp)
   678				return -ENOMEM;
   679	
   680			ret = of_property_read_u32_array(opp->np, name, microamp, icount);
   681			if (ret) {
   682				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   683				ret = -EINVAL;
   684				goto free_microamp;
   685			}
   686		}
   687	
   688		/* Search for "opp-microwatt-<name>" */
   689		if (opp_table->prop_name) {
   690			snprintf(name, sizeof(name), "opp-microwatt-%s",
   691				 opp_table->prop_name);
   692			prop_mw = of_find_property(opp->np, name, NULL);
   693		}
   694	
   695		if (!prop_mw) {
   696			/* Search for "opp-microwatt" */
   697			sprintf(name, "opp-microwatt");
   698			prop_mw = of_find_property(opp->np, name, NULL);
   699	
   700		}
   701	
   702		if (prop_mw) {
   703			pcount = of_property_count_u32_elems(opp->np, name);
   704			if (unlikely(supplies == -1))
   705				supplies = opp_table->regulator_count = pcount;
   706		} else {
   707			prop_mw = NULL;
   708			pcount = 0;
   709		}
   710	
   711		if (pcount < 0) {
   712			dev_err(dev, "%s: Invalid %s property (%d)\n",
   713				__func__, name, pcount);
   714			return pcount;
   715		}
   716	
   717		if (pcount) {
   718			/* There can be one or three elements per supply */
   719			if (pcount != supplies && pcount != supplies * 3) {
   720				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   721					__func__, name, pcount, supplies);
   722				return -EINVAL;
   723			}
   724	
   725			microwatt = kmalloc_array(pcount, sizeof(*microwatt), GFP_KERNEL);
   726			if (!microwatt)
   727				return -ENOMEM;
   728	
   729			ret = of_property_read_u32_array(opp->np, name, microwatt, pcount);
   730			if (ret) {
   731				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   732				ret = -EINVAL;
   733				goto free_microwatt;
   734			}
   735		}
   736	
   737		/* No supplies associated with the OPP */
   738		if (unlikely(supplies == -1)) {
 > 739			opp->regulator_count = 0;
   740			return 0;
   741		}
   742	
   743		for (i = 0, j = 0; i < supplies; i++) {
   744			if (microvolt) {
   745				opp->supplies[i].u_volt = microvolt[j++];
   746	
   747				if (vcount == supplies) {
   748					opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
   749					opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
   750				} else {
   751					opp->supplies[i].u_volt_min = microvolt[j++];
   752					opp->supplies[i].u_volt_max = microvolt[j++];
   753				}
   754			}
   755	
   756			if (microamp)
   757				opp->supplies[i].u_amp = microamp[i];
   758	
   759			if (microwatt)
   760				opp->supplies[i].u_watt = microwatt[i];
   761		}
   762	
   763	free_microwatt:
   764		kfree(microwatt);
   765	free_microamp:
   766		kfree(microamp);
   767	free_microvolt:
   768		kfree(microvolt);
   769	
   770		return ret;
   771	}
   772
  
kernel test robot Oct. 30, 2022, 5:34 a.m. UTC | #2
Hi James,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.1-rc2 next-20221028]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/James-Calligeros/OPP-decouple-dt-properties-in-opp_parse_supplies/20221030-114618
patch link:    https://lore.kernel.org/r/20221030034414.24672-1-jcalligeros99%40gmail.com
patch subject: [PATCH] OPP: decouple dt properties in opp_parse_supplies()
config: riscv-randconfig-r042-20221030
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 791a7ae1ba3efd6bca96338e10ffde557ba83920)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install riscv cross compiling tool for clang build
        # apt-get install binutils-riscv64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/c88dea73d372f38c7f3ab19f688cf210d49481ea
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review James-Calligeros/OPP-decouple-dt-properties-in-opp_parse_supplies/20221030-114618
        git checkout c88dea73d372f38c7f3ab19f688cf210d49481ea
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash drivers/opp/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/opp/of.c:739:8: error: no member named 'regulator_count' in 'struct dev_pm_opp'
                   opp->regulator_count = 0;
                   ~~~  ^
   1 error generated.


vim +739 drivers/opp/of.c

   580	
   581	static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
   582				      struct opp_table *opp_table)
   583	{
   584		u32 *microvolt = NULL, *microamp = NULL, *microwatt = NULL;
   585		int supplies = opp_table->regulator_count;
   586		int vcount, icount, pcount, ret, i, j;
   587		struct property *prop_mv = NULL, *prop_ma = NULL, *prop_mw = NULL;
   588		char name[NAME_MAX];
   589	
   590		/* Search for "opp-microvolt-<name>" */
   591		if (opp_table->prop_name) {
   592			snprintf(name, sizeof(name), "opp-microvolt-%s",
   593				 opp_table->prop_name);
   594			prop_mv = of_find_property(opp->np, name, NULL);
   595		}
   596	
   597		if (!prop_mv) {
   598			/* Search for "opp-microvolt" */
   599			sprintf(name, "opp-microvolt");
   600			prop_mv = of_find_property(opp->np, name, NULL);
   601	
   602		}
   603	
   604		if (prop_mv) {
   605			vcount = of_property_count_u32_elems(opp->np, name);
   606			if (unlikely(supplies == -1))
   607				supplies = opp_table->regulator_count = vcount;
   608		} else {
   609			prop_mv = NULL;
   610			vcount = 0;
   611		}
   612	
   613		if (vcount < 0) {
   614			dev_err(dev, "%s: Invalid %s property (%d)\n",
   615				__func__, name, vcount);
   616			return vcount;
   617		}
   618	
   619		if (vcount) {
   620			/* There can be one or three elements per supply */
   621			if (vcount != supplies && vcount != supplies * 3) {
   622				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   623					__func__, name, vcount, supplies);
   624				return -EINVAL;
   625			}
   626	
   627			microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
   628			if (!microvolt)
   629				return -ENOMEM;
   630	
   631			ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
   632			if (ret) {
   633				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   634				ret = -EINVAL;
   635				goto free_microvolt;
   636			}
   637		}
   638	
   639		/* Search for "opp-microamp-<name>" */
   640		if (opp_table->prop_name) {
   641			snprintf(name, sizeof(name), "opp-microamp-%s",
   642				 opp_table->prop_name);
   643			prop_ma = of_find_property(opp->np, name, NULL);
   644		}
   645	
   646		if (!prop_ma) {
   647			/* Search for "opp-microamp" */
   648			sprintf(name, "opp-microamp");
   649			prop_ma = of_find_property(opp->np, name, NULL);
   650	
   651		}
   652	
   653		if (prop_ma) {
   654			icount = of_property_count_u32_elems(opp->np, name);
   655			if (unlikely(supplies == -1))
   656				supplies = opp_table->regulator_count = icount;
   657		} else {
   658			prop_ma = NULL;
   659			icount = 0;
   660		}
   661	
   662		if (icount < 0) {
   663			dev_err(dev, "%s: Invalid %s property (%d)\n",
   664				__func__, name, icount);
   665			return icount;
   666		}
   667	
   668		if (icount) {
   669			/* There can be one or three elements per supply */
   670			if (icount != supplies && icount != supplies * 3) {
   671				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   672					__func__, name, icount, supplies);
   673				return -EINVAL;
   674			}
   675	
   676			microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
   677			if (!microamp)
   678				return -ENOMEM;
   679	
   680			ret = of_property_read_u32_array(opp->np, name, microamp, icount);
   681			if (ret) {
   682				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   683				ret = -EINVAL;
   684				goto free_microamp;
   685			}
   686		}
   687	
   688		/* Search for "opp-microwatt-<name>" */
   689		if (opp_table->prop_name) {
   690			snprintf(name, sizeof(name), "opp-microwatt-%s",
   691				 opp_table->prop_name);
   692			prop_mw = of_find_property(opp->np, name, NULL);
   693		}
   694	
   695		if (!prop_mw) {
   696			/* Search for "opp-microwatt" */
   697			sprintf(name, "opp-microwatt");
   698			prop_mw = of_find_property(opp->np, name, NULL);
   699	
   700		}
   701	
   702		if (prop_mw) {
   703			pcount = of_property_count_u32_elems(opp->np, name);
   704			if (unlikely(supplies == -1))
   705				supplies = opp_table->regulator_count = pcount;
   706		} else {
   707			prop_mw = NULL;
   708			pcount = 0;
   709		}
   710	
   711		if (pcount < 0) {
   712			dev_err(dev, "%s: Invalid %s property (%d)\n",
   713				__func__, name, pcount);
   714			return pcount;
   715		}
   716	
   717		if (pcount) {
   718			/* There can be one or three elements per supply */
   719			if (pcount != supplies && pcount != supplies * 3) {
   720				dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
   721					__func__, name, pcount, supplies);
   722				return -EINVAL;
   723			}
   724	
   725			microwatt = kmalloc_array(pcount, sizeof(*microwatt), GFP_KERNEL);
   726			if (!microwatt)
   727				return -ENOMEM;
   728	
   729			ret = of_property_read_u32_array(opp->np, name, microwatt, pcount);
   730			if (ret) {
   731				dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
   732				ret = -EINVAL;
   733				goto free_microwatt;
   734			}
   735		}
   736	
   737		/* No supplies associated with the OPP */
   738		if (unlikely(supplies == -1)) {
 > 739			opp->regulator_count = 0;
   740			return 0;
   741		}
   742	
   743		for (i = 0, j = 0; i < supplies; i++) {
   744			if (microvolt) {
   745				opp->supplies[i].u_volt = microvolt[j++];
   746	
   747				if (vcount == supplies) {
   748					opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
   749					opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
   750				} else {
   751					opp->supplies[i].u_volt_min = microvolt[j++];
   752					opp->supplies[i].u_volt_max = microvolt[j++];
   753				}
   754			}
   755	
   756			if (microamp)
   757				opp->supplies[i].u_amp = microamp[i];
   758	
   759			if (microwatt)
   760				opp->supplies[i].u_watt = microwatt[i];
   761		}
   762	
   763	free_microwatt:
   764		kfree(microwatt);
   765	free_microamp:
   766		kfree(microamp);
   767	free_microvolt:
   768		kfree(microvolt);
   769	
   770		return ret;
   771	}
   772
  

Patch

diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 605d68673f92..0fa25c3a959e 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -581,166 +581,176 @@  static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
 static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
 			      struct opp_table *opp_table)
 {
-	u32 *microvolt, *microamp = NULL, *microwatt = NULL;
+	u32 *microvolt = NULL, *microamp = NULL, *microwatt = NULL;
 	int supplies = opp_table->regulator_count;
 	int vcount, icount, pcount, ret, i, j;
-	struct property *prop = NULL;
+	struct property *prop_mv = NULL, *prop_ma = NULL, *prop_mw = NULL;
 	char name[NAME_MAX];
 
 	/* Search for "opp-microvolt-<name>" */
 	if (opp_table->prop_name) {
 		snprintf(name, sizeof(name), "opp-microvolt-%s",
 			 opp_table->prop_name);
-		prop = of_find_property(opp->np, name, NULL);
+		prop_mv = of_find_property(opp->np, name, NULL);
 	}
 
-	if (!prop) {
+	if (!prop_mv) {
 		/* Search for "opp-microvolt" */
 		sprintf(name, "opp-microvolt");
-		prop = of_find_property(opp->np, name, NULL);
-
-		/* Missing property isn't a problem, but an invalid entry is */
-		if (!prop) {
-			if (unlikely(supplies == -1)) {
-				/* Initialize regulator_count */
-				opp_table->regulator_count = 0;
-				return 0;
-			}
+		prop_mv = of_find_property(opp->np, name, NULL);
 
-			if (!supplies)
-				return 0;
-
-			dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
-				__func__);
-			return -EINVAL;
-		}
 	}
 
-	if (unlikely(supplies == -1)) {
-		/* Initialize regulator_count */
-		supplies = opp_table->regulator_count = 1;
-	} else if (unlikely(!supplies)) {
-		dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
-		return -EINVAL;
+	if (prop_mv) {
+		vcount = of_property_count_u32_elems(opp->np, name);
+		if (unlikely(supplies == -1))
+			supplies = opp_table->regulator_count = vcount;
+	} else {
+		prop_mv = NULL;
+		vcount = 0;
 	}
 
-	vcount = of_property_count_u32_elems(opp->np, name);
 	if (vcount < 0) {
 		dev_err(dev, "%s: Invalid %s property (%d)\n",
 			__func__, name, vcount);
 		return vcount;
 	}
 
-	/* There can be one or three elements per supply */
-	if (vcount != supplies && vcount != supplies * 3) {
-		dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
-			__func__, name, vcount, supplies);
-		return -EINVAL;
-	}
+	if (vcount) {
+		/* There can be one or three elements per supply */
+		if (vcount != supplies && vcount != supplies * 3) {
+			dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
+				__func__, name, vcount, supplies);
+			return -EINVAL;
+		}
 
-	microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
-	if (!microvolt)
-		return -ENOMEM;
+		microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
+		if (!microvolt)
+			return -ENOMEM;
 
-	ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
-	if (ret) {
-		dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
-		ret = -EINVAL;
-		goto free_microvolt;
+		ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
+		if (ret) {
+			dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
+			ret = -EINVAL;
+			goto free_microvolt;
+		}
 	}
 
 	/* Search for "opp-microamp-<name>" */
-	prop = NULL;
 	if (opp_table->prop_name) {
 		snprintf(name, sizeof(name), "opp-microamp-%s",
 			 opp_table->prop_name);
-		prop = of_find_property(opp->np, name, NULL);
+		prop_ma = of_find_property(opp->np, name, NULL);
 	}
 
-	if (!prop) {
+	if (!prop_ma) {
 		/* Search for "opp-microamp" */
 		sprintf(name, "opp-microamp");
-		prop = of_find_property(opp->np, name, NULL);
+		prop_ma = of_find_property(opp->np, name, NULL);
+
 	}
 
-	if (prop) {
+	if (prop_ma) {
 		icount = of_property_count_u32_elems(opp->np, name);
-		if (icount < 0) {
-			dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
-				name, icount);
-			ret = icount;
-			goto free_microvolt;
-		}
+		if (unlikely(supplies == -1))
+			supplies = opp_table->regulator_count = icount;
+	} else {
+		prop_ma = NULL;
+		icount = 0;
+	}
 
-		if (icount != supplies) {
+	if (icount < 0) {
+		dev_err(dev, "%s: Invalid %s property (%d)\n",
+			__func__, name, icount);
+		return icount;
+	}
+
+	if (icount) {
+		/* There can be one or three elements per supply */
+		if (icount != supplies && icount != supplies * 3) {
 			dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
 				__func__, name, icount, supplies);
-			ret = -EINVAL;
-			goto free_microvolt;
+			return -EINVAL;
 		}
 
 		microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
-		if (!microamp) {
-			ret = -EINVAL;
-			goto free_microvolt;
-		}
+		if (!microamp)
+			return -ENOMEM;
 
-		ret = of_property_read_u32_array(opp->np, name, microamp,
-						 icount);
+		ret = of_property_read_u32_array(opp->np, name, microamp, icount);
 		if (ret) {
-			dev_err(dev, "%s: error parsing %s: %d\n", __func__,
-				name, ret);
+			dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
 			ret = -EINVAL;
 			goto free_microamp;
 		}
 	}
 
-	/* Search for "opp-microwatt" */
-	sprintf(name, "opp-microwatt");
-	prop = of_find_property(opp->np, name, NULL);
+	/* Search for "opp-microwatt-<name>" */
+	if (opp_table->prop_name) {
+		snprintf(name, sizeof(name), "opp-microwatt-%s",
+			 opp_table->prop_name);
+		prop_mw = of_find_property(opp->np, name, NULL);
+	}
+
+	if (!prop_mw) {
+		/* Search for "opp-microwatt" */
+		sprintf(name, "opp-microwatt");
+		prop_mw = of_find_property(opp->np, name, NULL);
 
-	if (prop) {
+	}
+
+	if (prop_mw) {
 		pcount = of_property_count_u32_elems(opp->np, name);
-		if (pcount < 0) {
-			dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
-				name, pcount);
-			ret = pcount;
-			goto free_microamp;
-		}
+		if (unlikely(supplies == -1))
+			supplies = opp_table->regulator_count = pcount;
+	} else {
+		prop_mw = NULL;
+		pcount = 0;
+	}
+
+	if (pcount < 0) {
+		dev_err(dev, "%s: Invalid %s property (%d)\n",
+			__func__, name, pcount);
+		return pcount;
+	}
 
-		if (pcount != supplies) {
+	if (pcount) {
+		/* There can be one or three elements per supply */
+		if (pcount != supplies && pcount != supplies * 3) {
 			dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
 				__func__, name, pcount, supplies);
-			ret = -EINVAL;
-			goto free_microamp;
+			return -EINVAL;
 		}
 
-		microwatt = kmalloc_array(pcount, sizeof(*microwatt),
-					  GFP_KERNEL);
-		if (!microwatt) {
-			ret = -EINVAL;
-			goto free_microamp;
-		}
+		microwatt = kmalloc_array(pcount, sizeof(*microwatt), GFP_KERNEL);
+		if (!microwatt)
+			return -ENOMEM;
 
-		ret = of_property_read_u32_array(opp->np, name, microwatt,
-						 pcount);
+		ret = of_property_read_u32_array(opp->np, name, microwatt, pcount);
 		if (ret) {
-			dev_err(dev, "%s: error parsing %s: %d\n", __func__,
-				name, ret);
+			dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
 			ret = -EINVAL;
 			goto free_microwatt;
 		}
 	}
 
-	for (i = 0, j = 0; i < supplies; i++) {
-		opp->supplies[i].u_volt = microvolt[j++];
+	/* No supplies associated with the OPP */
+	if (unlikely(supplies == -1)) {
+		opp->regulator_count = 0;
+		return 0;
+	}
 
-		if (vcount == supplies) {
-			opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
-			opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
-		} else {
-			opp->supplies[i].u_volt_min = microvolt[j++];
-			opp->supplies[i].u_volt_max = microvolt[j++];
+	for (i = 0, j = 0; i < supplies; i++) {
+		if (microvolt) {
+			opp->supplies[i].u_volt = microvolt[j++];
+
+			if (vcount == supplies) {
+				opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
+				opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+			} else {
+				opp->supplies[i].u_volt_min = microvolt[j++];
+				opp->supplies[i].u_volt_max = microvolt[j++];
+			}
 		}
 
 		if (microamp)