[alsa-devel] [PATCH 06/16] regulator: madera-ldo1: LDO1 driver for Cirrus Logic Madera codecs

Richard Fitzgerald rf at opensource.wolfsonmicro.com
Wed Apr 5 12:07:54 CEST 2017


This patch adds a driver for the internal LDO1 regulator on
some Cirrus Logic Madera class codecs.

Signed-off-by: Richard Fitzgerald <rf at opensource.wolfsonmicro.com>
Signed-off-by: Charles Keepax <ckeepax at opensource.wolfsonmicro.com>
---
 .../devicetree/bindings/regulator/madera-ldo1.txt  |  29 +++
 MAINTAINERS                                        |   3 +
 drivers/regulator/Kconfig                          |   8 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/madera-ldo1.c                    | 198 +++++++++++++++++++++
 include/linux/regulator/madera-ldo1.h              |  24 +++
 6 files changed, 263 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/madera-ldo1.txt
 create mode 100644 drivers/regulator/madera-ldo1.c
 create mode 100644 include/linux/regulator/madera-ldo1.h

diff --git a/Documentation/devicetree/bindings/regulator/madera-ldo1.txt b/Documentation/devicetree/bindings/regulator/madera-ldo1.txt
new file mode 100644
index 0000000..688f21d
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/madera-ldo1.txt
@@ -0,0 +1,29 @@
+Cirrus Logic Madera class audio codecs LDO1 regulator driver
+
+Only required if you are using the codec internal LDO1 regulator.
+This is a subnode of the parent mfd node.
+
+See also the core bindings for the parent MFD driver:
+See Documentation/devicetree/bindings/mfd/madera.txt
+
+Required properties:
+  - compatible :  must be "cirrus,madera-ldo1"
+  - LDOVDD-supply : Power supply for the LDO1 regulator.
+
+  - enable-gpio	: GPIO to use to enable/disable the regulator.
+    As defined in bindings/gpio.txt.
+
+Optional subnodes:
+  Standard regulator bindings as described in bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs47l85 at 0 {
+	compatible = "cirrus,cs47l85";
+
+	ldo1 {
+		compatible = "cirrus,madera-ldo1";
+		LDOVDD-supply = <&pmic_vdd1>;
+		enable-gpio = <&gpio 0>;
+	};
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index d28e53f..1207c9c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3267,9 +3267,12 @@ T:	git https://github.com/CirrusLogic/linux-drivers.git
 W:	https://github.com/CirrusLogic/linux-drivers/wiki
 S:	Supported
 F:	Documentation/devicetree/bindings/mfd/madera.txt
+F:	Documentation/devicetree/bindings/regulator/madera*
 F:	include/linux/mfd/madera/*
+F:	include/linux/regulator/madera*
 F:	drivers/mfd/madera*
 F:	drivers/mfd/cs47l*
+F:	drivers/regulator/madera*
 
 CLEANCACHE API
 M:	Konrad Rzeszutek Wilk <konrad.wilk at oracle.com>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index be06eb2..c96d9a6 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -368,6 +368,14 @@ config REGULATOR_LTC3676
 	  This enables support for the LTC3676
 	  8-output regulators controlled via I2C.
 
+config REGULATOR_MADERA_LDO1
+	tristate "Cirrus Logic Madera codecs LDO1 regulator"
+	depends on MFD_MADERA
+	help
+	  If you want to use the internal LDO1 regulator on CS47L85 and WM1840
+	  to supply DCVDD you must include this driver. If you are using an
+	  external DCVDD regulator you do not need this driver.
+
 config REGULATOR_MAX14577
 	tristate "Maxim 14577/77836 regulator"
 	depends on MFD_MAX14577
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ef7725e..2db3592 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
 obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
 obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
 obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o
+obj-$(CONFIG_REGULATOR_MADERA_LDO1) += madera-ldo1.o
 obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
diff --git a/drivers/regulator/madera-ldo1.c b/drivers/regulator/madera-ldo1.c
new file mode 100644
index 0000000..6504d6f
--- /dev/null
+++ b/drivers/regulator/madera-ldo1.c
@@ -0,0 +1,198 @@
+/*
+ * madera-ldo1.c  --  Driver for the LDO1 regulator on Madera codecs
+ *
+ * Copyright 2015-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <linux/regulator/madera-ldo1.h>
+
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
+struct madera_ldo1 {
+	struct regulator_dev *regulator;
+
+	struct regulator_consumer_supply supply;
+	struct regulator_init_data init_data;
+};
+
+static const struct regulator_ops madera_ldo1_ops = {
+	.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,
+};
+
+static const struct regulator_desc madera_ldo1 = {
+	.name = "LDO1",
+	.supply_name = "LDOVDD",
+	.type = REGULATOR_VOLTAGE,
+	.ops = &madera_ldo1_ops,
+
+	.vsel_reg = MADERA_LDO1_CONTROL_1,
+	.vsel_mask = MADERA_LDO1_VSEL_MASK,
+	.min_uV = 900000,
+	.uV_step = 25000,
+	.n_voltages = 13,
+	.enable_time = 3000,
+
+	.owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data madera_ldo1_default = {
+	.constraints = {
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies = 1,
+};
+
+static int madera_ldo1_of_get_pdata(struct madera *madera,
+				    struct regulator_config *config,
+				    const struct regulator_desc *desc)
+{
+	struct madera_pdata *pdata = &madera->pdata;
+	struct madera_ldo1 *ldo1 = config->driver_data;
+	struct device_node *dcvdd_node;
+	struct regulator_init_data *init_data;
+
+	dcvdd_node = of_parse_phandle(madera->dev->of_node, "DCVDD-supply", 0);
+
+	init_data = of_get_regulator_init_data(config->dev,
+					       config->dev->of_node,
+					       desc);
+	if (init_data) {
+		init_data->consumer_supplies = &ldo1->supply;
+		init_data->num_consumer_supplies = 1;
+		pdata->ldo1.init_data = init_data;
+
+		/* Check whether we're supplying the codec's DCVDD */
+		if (dcvdd_node && dcvdd_node != config->dev->of_node)
+			madera->internal_dcvdd = false;
+	} else if (dcvdd_node) {
+		madera->internal_dcvdd = false;
+	}
+
+	of_node_put(dcvdd_node);
+
+	if (madera->internal_dcvdd) {
+		pdata->ldo1.ldoena = of_get_named_gpio(madera->dev->of_node,
+						       "enable-gpio", 0);
+		if (pdata->ldo1.ldoena < 0)
+			if (pdata->ldo1.ldoena != -ENOENT)
+				dev_warn(madera->dev,
+					 "Malformed enable-gpio ignored: %d\n",
+					 pdata->ldo1.ldoena);
+	}
+
+	return 0;
+}
+
+static int madera_ldo1_probe(struct platform_device *pdev)
+{
+	struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+	const struct regulator_desc *desc;
+	struct regulator_config config = { };
+	struct madera_ldo1 *ldo1;
+	int ret;
+
+	madera->internal_dcvdd = true;
+
+	ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+	if (!ldo1)
+		return -ENOMEM;
+
+	/*
+	 * Since the chip usually supplies itself we provide some
+	 * default init_data for it.  This will be overridden with
+	 * platform data if provided.
+	 */
+	desc = &madera_ldo1;
+	ldo1->init_data = madera_ldo1_default;
+
+	ldo1->init_data.consumer_supplies = &ldo1->supply;
+	ldo1->supply.supply = "DCVDD";
+	ldo1->supply.dev_name = dev_name(madera->dev);
+
+	config.dev = &pdev->dev;
+	config.of_node = config.dev->of_node;
+	config.driver_data = ldo1;
+	config.regmap = madera->regmap;
+
+	/* pdata defaults to 0 if not explicitly set. Convert to invalid. */
+	if (madera->pdata.ldo1.ldoena == 0)
+		madera->pdata.ldo1.ldoena = -EINVAL;
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(madera->dev)) {
+			ret = madera_ldo1_of_get_pdata(madera, &config, desc);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	if (madera->pdata.ldo1.init_data)
+		ldo1->init_data = *madera->pdata.ldo1.init_data;
+
+	if (gpio_is_valid(madera->pdata.ldo1.ldoena)) {
+		config.ena_gpio = madera->pdata.ldo1.ldoena;
+		config.ena_gpio_initialized = true;
+	} else {
+		dev_warn(madera->dev,
+			 "Running without LDOENA is not recommended\n");
+	}
+	config.ena_gpio_flags = GPIOF_OUT_INIT_LOW;
+	config.init_data = &ldo1->init_data;
+
+	/*
+	 * LDO1 can only be used to supply DCVDD so if it has no
+	 * consumers then DCVDD is supplied externally.
+	 */
+	if (config.init_data->num_consumer_supplies == 0)
+		madera->internal_dcvdd = false;
+
+	ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);
+
+	of_node_put(config.of_node);
+
+	if (IS_ERR(ldo1->regulator)) {
+		ret = PTR_ERR(ldo1->regulator);
+		dev_err(madera->dev, "Failed to register LDO1 supply: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver madera_ldo1_driver = {
+	.probe = madera_ldo1_probe,
+	.driver		= {
+		.name	= "madera-ldo1",
+	},
+};
+
+module_platform_driver(madera_ldo1_driver);
+
+MODULE_DESCRIPTION("Madera LDO1 driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax at opensource.wolfsonmicro.com>");
+MODULE_AUTHOR("Richard Fitzgerald <rf at opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:madera-ldo1");
diff --git a/include/linux/regulator/madera-ldo1.h b/include/linux/regulator/madera-ldo1.h
new file mode 100644
index 0000000..9435021
--- /dev/null
+++ b/include/linux/regulator/madera-ldo1.h
@@ -0,0 +1,24 @@
+/*
+ * Platform data for Madera codecs LDO1 regulator
+ *
+ * Copyright 2016-2017 Cirrus Logic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MADERA_LDO1_H
+#define MADERA_LDO1_H
+
+struct regulator_init_data;
+
+struct madera_ldo1_pdata {
+	/** GPIO controlling LODENA, if any */
+	int ldoena;
+
+	/** Regulator configuration for LDO1 */
+	const struct regulator_init_data *init_data;
+};
+
+#endif
-- 
1.9.1



More information about the Alsa-devel mailing list