diff mbox

[v2,6/8] regulator: arizona-micbias: Add regulator driver for Arizona micbiases

Message ID 1490710484-25277-6-git-send-email-ckeepax@opensource.wolfsonmicro.com (mailing list archive)
State New, archived
Headers show

Commit Message

Charles Keepax March 28, 2017, 2:14 p.m. UTC
Add a driver for controlling the micbias regulators on the Arizona class
audio CODECs. This will replace earlier fixed support that initialised
the micbias's with fixed settings from platform data, although that
platform data can still be used to configure the constraints on this new
regulator.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---

Changes since v1:
 - Use active_discharge rather than pull_down as that is what the
   regulator actually does.
 - Pass the micbias device rather than the arizona device to
   of_get_regulator_init_data to avoid leaking init_data
 - Update the pdata to use an actual regulator_init_data
 - Tidy up the code to make it a little easier to follow

 drivers/regulator/Makefile          |   2 +-
 drivers/regulator/arizona-micbias.c | 228 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/arizona/pdata.h   |   6 +-
 3 files changed, 231 insertions(+), 5 deletions(-)
 create mode 100644 drivers/regulator/arizona-micbias.c

Comments

kernel test robot March 29, 2017, 6:18 a.m. UTC | #1
Hi Charles,

[auto build test WARNING on regulator/for-next]
[also build test WARNING on v4.11-rc4 next-20170328]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Keepax/regulator-arizona-micsupp-Avoid-potential-memory-leak-reading-init_data/20170329-112224
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
config: i386-randconfig-x0-03291136 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from include/linux/err.h:4:0,
                    from include/linux/clk.h:15,
                    from drivers//mfd/arizona-core.c:13:
   drivers//mfd/arizona-core.c: In function 'arizona_dev_init':
   drivers//mfd/arizona-core.c:1408:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV &&
                                    ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1409:33: error: 'struct arizona_micbias' has no member named 'bypass'
          !arizona->pdata.micbias[i].bypass)
                                    ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1408:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV &&
                                    ^
   include/linux/compiler.h:160:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1409:33: error: 'struct arizona_micbias' has no member named 'bypass'
          !arizona->pdata.micbias[i].bypass)
                                    ^
   include/linux/compiler.h:160:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1408:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV &&
                                    ^
   include/linux/compiler.h:171:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1409:33: error: 'struct arizona_micbias' has no member named 'bypass'
          !arizona->pdata.micbias[i].bypass)
                                    ^
   include/linux/compiler.h:171:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
>> drivers//mfd/arizona-core.c:1408:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV &&
      ^~
   drivers//mfd/arizona-core.c:1413:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV)
                                    ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
   drivers//mfd/arizona-core.c:1413:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV)
      ^~
   drivers//mfd/arizona-core.c:1413:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV)
                                    ^
   include/linux/compiler.h:160:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
   drivers//mfd/arizona-core.c:1413:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV)
      ^~
   drivers//mfd/arizona-core.c:1413:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV)
                                    ^
   include/linux/compiler.h:171:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
   drivers//mfd/arizona-core.c:1413:3: note: in expansion of macro 'if'
      if (!arizona->pdata.micbias[i].mV)
      ^~
   drivers//mfd/arizona-core.c:1414:29: error: 'struct arizona_micbias' has no member named 'mV'
       arizona->pdata.micbias[i].mV = 2800;
                                ^
   drivers//mfd/arizona-core.c:1416:35: error: 'struct arizona_micbias' has no member named 'mV'
      val = (arizona->pdata.micbias[i].mV - 1500) / 100;
                                      ^
   In file included from include/linux/err.h:4:0,
                    from include/linux/clk.h:15,
                    from drivers//mfd/arizona-core.c:13:
   drivers//mfd/arizona-core.c:1423:32: error: 'struct arizona_micbias' has no member named 'discharge'
      if (arizona->pdata.micbias[i].discharge)
                                   ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
   drivers//mfd/arizona-core.c:1423:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].discharge)
      ^~
   drivers//mfd/arizona-core.c:1423:32: error: 'struct arizona_micbias' has no member named 'discharge'
      if (arizona->pdata.micbias[i].discharge)
                                   ^
   include/linux/compiler.h:160:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
   drivers//mfd/arizona-core.c:1423:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].discharge)
      ^~
   drivers//mfd/arizona-core.c:1423:32: error: 'struct arizona_micbias' has no member named 'discharge'
      if (arizona->pdata.micbias[i].discharge)
                                   ^
   include/linux/compiler.h:171:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
   drivers//mfd/arizona-core.c:1423:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].discharge)
      ^~
   drivers//mfd/arizona-core.c:1426:32: error: 'struct arizona_micbias' has no member named 'soft_start'
      if (arizona->pdata.micbias[i].soft_start)
                                   ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
   drivers//mfd/arizona-core.c:1426:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].soft_start)
      ^~
   drivers//mfd/arizona-core.c:1426:32: error: 'struct arizona_micbias' has no member named 'soft_start'
      if (arizona->pdata.micbias[i].soft_start)
                                   ^
   include/linux/compiler.h:160:42: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                             ^~~~
   drivers//mfd/arizona-core.c:1426:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].soft_start)
      ^~
   drivers//mfd/arizona-core.c:1426:32: error: 'struct arizona_micbias' has no member named 'soft_start'
      if (arizona->pdata.micbias[i].soft_start)
                                   ^
   include/linux/compiler.h:171:16: note: in definition of macro '__trace_if'
      ______r = !!(cond);     \
                   ^~~~
   drivers//mfd/arizona-core.c:1426:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].soft_start)
      ^~
   drivers//mfd/arizona-core.c:1429:32: error: 'struct arizona_micbias' has no member named 'bypass'
      if (arizona->pdata.micbias[i].bypass)
                                   ^
   include/linux/compiler.h:160:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
   drivers//mfd/arizona-core.c:1429:3: note: in expansion of macro 'if'
      if (arizona->pdata.micbias[i].bypass)

vim +/if +1408 drivers//mfd/arizona-core.c

3cc72986 Mark Brown 2012-06-19  1392  				   ARIZONA_CLK_32K_SRC_MASK,
3cc72986 Mark Brown 2012-06-19  1393  				   arizona->pdata.clk32k_src - 1);
767c6dc0 Mark Brown 2013-03-19  1394  		arizona_clk32k_enable(arizona);
3cc72986 Mark Brown 2012-06-19  1395  		break;
3cc72986 Mark Brown 2012-06-19  1396  	case ARIZONA_32KZ_NONE:
3cc72986 Mark Brown 2012-06-19  1397  		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
3cc72986 Mark Brown 2012-06-19  1398  				   ARIZONA_CLK_32K_SRC_MASK, 2);
3cc72986 Mark Brown 2012-06-19  1399  		break;
3cc72986 Mark Brown 2012-06-19  1400  	default:
3cc72986 Mark Brown 2012-06-19  1401  		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
3cc72986 Mark Brown 2012-06-19  1402  			arizona->pdata.clk32k_src);
3cc72986 Mark Brown 2012-06-19  1403  		ret = -EINVAL;
59db9691 Mark Brown 2012-07-09  1404  		goto err_reset;
3cc72986 Mark Brown 2012-06-19  1405  	}
3cc72986 Mark Brown 2012-06-19  1406  
3d91f828 Mark Brown 2013-01-29  1407  	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
544c7aad Mark Brown 2013-01-29 @1408  		if (!arizona->pdata.micbias[i].mV &&
544c7aad Mark Brown 2013-01-29  1409  		    !arizona->pdata.micbias[i].bypass)
3d91f828 Mark Brown 2013-01-29  1410  			continue;
3d91f828 Mark Brown 2013-01-29  1411  
544c7aad Mark Brown 2013-01-29  1412  		/* Apply default for bypass mode */
544c7aad Mark Brown 2013-01-29  1413  		if (!arizona->pdata.micbias[i].mV)
544c7aad Mark Brown 2013-01-29  1414  			arizona->pdata.micbias[i].mV = 2800;
544c7aad Mark Brown 2013-01-29  1415  
3d91f828 Mark Brown 2013-01-29  1416  		val = (arizona->pdata.micbias[i].mV - 1500) / 100;

:::::: The code at line 1408 was first introduced by commit
:::::: 544c7aadd7d4309ed01fcd787d393db67eb7eaea mfd: arizona: Support configuring MICBIASes into bypass mode

:::::: TO: Mark Brown <broonie@opensource.wolfsonmicro.com>
:::::: CC: Samuel Ortiz <sameo@linux.intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Charles Keepax March 29, 2017, 8:30 a.m. UTC | #2
On Wed, Mar 29, 2017 at 02:18:23PM +0800, kbuild test robot wrote:
> Hi Charles,
> 
> [auto build test WARNING on regulator/for-next]
> [also build test WARNING on v4.11-rc4 next-20170328]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Charles-Keepax/regulator-arizona-micsupp-Avoid-potential-memory-leak-reading-init_data/20170329-112224
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
> config: i386-randconfig-x0-03291136 (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 

Hmm... this is due to the tree missing the patch that Lee already
applied from version 1. I guess perhaps we should pull that back
into this series or he could make an immutable branch you can pull
in?

Thanks,
Charles
kernel test robot March 29, 2017, 10:04 a.m. UTC | #3
Hi Charles,

[auto build test ERROR on regulator/for-next]
[also build test ERROR on v4.11-rc4 next-20170328]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Keepax/regulator-arizona-micsupp-Avoid-potential-memory-leak-reading-init_data/20170329-112224
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

   drivers//mfd/arizona-core.c: In function 'arizona_dev_init':
>> drivers//mfd/arizona-core.c:1408:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV &&
                                    ^
>> drivers//mfd/arizona-core.c:1409:33: error: 'struct arizona_micbias' has no member named 'bypass'
          !arizona->pdata.micbias[i].bypass)
                                    ^
   drivers//mfd/arizona-core.c:1413:33: error: 'struct arizona_micbias' has no member named 'mV'
      if (!arizona->pdata.micbias[i].mV)
                                    ^
   drivers//mfd/arizona-core.c:1414:29: error: 'struct arizona_micbias' has no member named 'mV'
       arizona->pdata.micbias[i].mV = 2800;
                                ^
   drivers//mfd/arizona-core.c:1416:35: error: 'struct arizona_micbias' has no member named 'mV'
      val = (arizona->pdata.micbias[i].mV - 1500) / 100;
                                      ^
>> drivers//mfd/arizona-core.c:1423:32: error: 'struct arizona_micbias' has no member named 'discharge'
      if (arizona->pdata.micbias[i].discharge)
                                   ^
>> drivers//mfd/arizona-core.c:1426:32: error: 'struct arizona_micbias' has no member named 'soft_start'
      if (arizona->pdata.micbias[i].soft_start)
                                   ^
   drivers//mfd/arizona-core.c:1429:32: error: 'struct arizona_micbias' has no member named 'bypass'
      if (arizona->pdata.micbias[i].bypass)
                                   ^

vim +1408 drivers//mfd/arizona-core.c

3cc72986 Mark Brown     2012-06-19  1402  			arizona->pdata.clk32k_src);
3cc72986 Mark Brown     2012-06-19  1403  		ret = -EINVAL;
59db9691 Mark Brown     2012-07-09  1404  		goto err_reset;
3cc72986 Mark Brown     2012-06-19  1405  	}
3cc72986 Mark Brown     2012-06-19  1406  
3d91f828 Mark Brown     2013-01-29  1407  	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
544c7aad Mark Brown     2013-01-29 @1408  		if (!arizona->pdata.micbias[i].mV &&
544c7aad Mark Brown     2013-01-29 @1409  		    !arizona->pdata.micbias[i].bypass)
3d91f828 Mark Brown     2013-01-29  1410  			continue;
3d91f828 Mark Brown     2013-01-29  1411  
544c7aad Mark Brown     2013-01-29  1412  		/* Apply default for bypass mode */
544c7aad Mark Brown     2013-01-29 @1413  		if (!arizona->pdata.micbias[i].mV)
544c7aad Mark Brown     2013-01-29 @1414  			arizona->pdata.micbias[i].mV = 2800;
544c7aad Mark Brown     2013-01-29  1415  
3d91f828 Mark Brown     2013-01-29  1416  		val = (arizona->pdata.micbias[i].mV - 1500) / 100;
544c7aad Mark Brown     2013-01-29  1417  
3d91f828 Mark Brown     2013-01-29  1418  		val <<= ARIZONA_MICB1_LVL_SHIFT;
3d91f828 Mark Brown     2013-01-29  1419  
3d91f828 Mark Brown     2013-01-29  1420  		if (arizona->pdata.micbias[i].ext_cap)
3d91f828 Mark Brown     2013-01-29  1421  			val |= ARIZONA_MICB1_EXT_CAP;
3d91f828 Mark Brown     2013-01-29  1422  
3d91f828 Mark Brown     2013-01-29 @1423  		if (arizona->pdata.micbias[i].discharge)
3d91f828 Mark Brown     2013-01-29  1424  			val |= ARIZONA_MICB1_DISCH;
3d91f828 Mark Brown     2013-01-29  1425  
f773fc6d Charles Keepax 2013-05-21 @1426  		if (arizona->pdata.micbias[i].soft_start)
3d91f828 Mark Brown     2013-01-29  1427  			val |= ARIZONA_MICB1_RATE;
3d91f828 Mark Brown     2013-01-29  1428  
544c7aad Mark Brown     2013-01-29  1429  		if (arizona->pdata.micbias[i].bypass)

:::::: The code at line 1408 was first introduced by commit
:::::: 544c7aadd7d4309ed01fcd787d393db67eb7eaea mfd: arizona: Support configuring MICBIASes into bypass mode

:::::: TO: Mark Brown <broonie@opensource.wolfsonmicro.com>
:::::: CC: Samuel Ortiz <sameo@linux.intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ef7725e..b670e87 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -19,7 +19,7 @@  obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o
 obj-$(CONFIG_REGULATOR_ACT8945A) += act8945a-regulator.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
-obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
+obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o arizona-micbias.o
 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
diff --git a/drivers/regulator/arizona-micbias.c b/drivers/regulator/arizona-micbias.c
new file mode 100644
index 0000000..622e659
--- /dev/null
+++ b/drivers/regulator/arizona-micbias.c
@@ -0,0 +1,228 @@ 
+/*
+ * arizona-micbias.c  --  Microphone bias supplies for Arizona devices
+ *
+ * Copyright 2017 Cirrus Logic Inc.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+#define ARIZONA_MICBIAS_MAX_SELECTOR 0xD
+
+struct arizona_micbias_priv {
+	int id;
+	struct arizona *arizona;
+
+	struct device_node *np;
+	struct regulator_desc desc;
+	struct regulator_consumer_supply supply;
+	struct regulator_init_data *init_data;
+
+	struct regulator_dev *regulator;
+};
+
+static const struct regulator_ops arizona_micbias_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.map_voltage = regulator_map_voltage_linear,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
+	.set_soft_start = regulator_set_soft_start_regmap,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+static const struct regulator_desc arizona_micbias_desc_tmpl = {
+	.supply_name = "MICVDD",
+	.type = REGULATOR_VOLTAGE,
+	.ops = &arizona_micbias_ops,
+
+	.min_uV = 1500000,
+	.uV_step = 100000,
+	.n_voltages = ARIZONA_MICBIAS_MAX_SELECTOR + 1,
+
+	.vsel_reg = ARIZONA_MIC_BIAS_CTRL_1,
+	.vsel_mask = ARIZONA_MICB1_LVL_MASK,
+	.enable_reg = ARIZONA_MIC_BIAS_CTRL_1,
+	.enable_mask = ARIZONA_MICB1_ENA,
+	.bypass_reg = ARIZONA_MIC_BIAS_CTRL_1,
+	.bypass_mask = ARIZONA_MICB1_BYPASS,
+	.soft_start_reg = ARIZONA_MIC_BIAS_CTRL_1,
+	.soft_start_mask = ARIZONA_MICB1_RATE,
+	.active_discharge_reg = ARIZONA_MIC_BIAS_CTRL_1,
+	.active_discharge_mask = ARIZONA_MICB1_DISCH,
+	.active_discharge_on = ARIZONA_MICB1_DISCH,
+
+	.owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_micbias_tmpl = {
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS |
+				  REGULATOR_CHANGE_VOLTAGE |
+				  REGULATOR_CHANGE_BYPASS,
+		.min_uV = 1500000,
+		.max_uV = 2800000,
+	},
+};
+
+static int arizona_micbias_of_get_pdata(struct device *dev,
+					struct device_node *np,
+					struct arizona_micbias_priv *micbias)
+{
+	struct arizona *arizona = micbias->arizona;
+	struct arizona_micbias *pdata = &arizona->pdata.micbias[micbias->id];
+
+	micbias->np = of_get_child_by_name(np, micbias->desc.name);
+	if (micbias->np) {
+		micbias->init_data = of_get_regulator_init_data(dev,
+								micbias->np,
+								&micbias->desc);
+
+		pdata->ext_cap = of_property_read_bool(micbias->np,
+						       "wlf,ext-cap");
+	}
+
+	return 0;
+}
+
+static int arizona_micbias_init_pdata(struct device *dev,
+				      struct arizona_micbias_priv *micbias)
+{
+	struct arizona *arizona = micbias->arizona;
+	struct arizona_micbias *pdata = &arizona->pdata.micbias[micbias->id];
+	int ret;
+
+	if (pdata->init_data)
+		return 0;
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		struct device_node *np = arizona->dev->of_node;
+
+		ret = arizona_micbias_of_get_pdata(dev, np, micbias);
+		if (ret < 0) {
+			dev_err(dev, "Failed to parse DT: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (!micbias->init_data) {
+		micbias->init_data = devm_kmemdup(dev,
+						  &arizona_micbias_tmpl,
+						  sizeof(arizona_micbias_tmpl),
+						  GFP_KERNEL);
+		if (!micbias->init_data)
+			return -ENOMEM;
+	}
+
+	micbias->supply.supply = micbias->desc.name;
+	micbias->supply.dev_name = dev_name(arizona->dev);
+
+	micbias->init_data->consumer_supplies = &micbias->supply;
+	micbias->init_data->num_consumer_supplies = 1;
+
+	pdata->init_data = micbias->init_data;
+
+	return 0;
+}
+
+static int arizona_micbias_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	int id = pdev->id;
+	struct arizona_micbias *pdata = &arizona->pdata.micbias[id];
+	struct arizona_micbias_priv *micbias;
+	struct regulator_config config = { };
+	unsigned int val;
+	int ret;
+
+	micbias = devm_kzalloc(&pdev->dev, sizeof(*micbias), GFP_KERNEL);
+	if (micbias == NULL)
+		return -ENOMEM;
+
+	micbias->id = id;
+	micbias->arizona = arizona;
+
+	micbias->desc = arizona_micbias_desc_tmpl;
+	micbias->desc.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					    "MICBIAS%d", id + 1);
+	micbias->desc.vsel_reg += id;
+	micbias->desc.enable_reg += id;
+	micbias->desc.bypass_reg += id;
+	micbias->desc.soft_start_reg += id;
+	micbias->desc.pull_down_reg += id;
+
+	ret = arizona_micbias_init_pdata(&pdev->dev, micbias);
+	if (ret)
+		return ret;
+
+	if (pdata->ext_cap)
+		val = ARIZONA_MICB1_EXT_CAP;
+	else
+		val = 0;
+
+	/*
+	 * The core expects the regulator to have bypass disabled by default
+	 * so clear it, whilst we set the external cap.
+	 */
+	regmap_update_bits(arizona->regmap, ARIZONA_MIC_BIAS_CTRL_1 + id,
+			   ARIZONA_MICB1_EXT_CAP | ARIZONA_MICB1_BYPASS, val);
+
+	config.dev = arizona->dev;
+	config.regmap = arizona->regmap;
+	config.of_node = micbias->np;
+	config.init_data = pdata->init_data;
+	config.driver_data = micbias;
+
+	micbias->regulator = devm_regulator_register(&pdev->dev,
+						     &micbias->desc,
+						     &config);
+
+	of_node_put(config.of_node);
+
+	if (IS_ERR(micbias->regulator)) {
+		ret = PTR_ERR(micbias->regulator);
+		dev_err(arizona->dev, "Failed to register %s supply: %d\n",
+			micbias->desc.name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver arizona_micbias_driver = {
+	.probe = arizona_micbias_probe,
+	.driver		= {
+		.name	= "arizona-micbias",
+	},
+};
+
+module_platform_driver(arizona_micbias_driver);
+
+/* Module information */
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona microphone bias supply driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:arizona-micbias");
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 64faeef..89a3512 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -56,11 +56,9 @@ 
 struct regulator_init_data;
 
 struct arizona_micbias {
-	int mV;                    /** Regulated voltage */
+	/* Regulator configuration */
+	const struct regulator_init_data *init_data;
 	unsigned int ext_cap:1;    /** External capacitor fitted */
-	unsigned int discharge:1;  /** Actively discharge */
-	unsigned int soft_start:1; /** Disable aggressive startup ramp rate */
-	unsigned int bypass:1;     /** Use bypass mode */
 };
 
 struct arizona_micd_config {