All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lina Iyer <lina.iyer@linaro.org>
To: Georgi Djakov <georgi.djakov@linaro.org>
Cc: broonie@kernel.org, lgirdwood@gmail.com, andy.gross@linaro.org,
	sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
	linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH v4] regulator: qcom-saw: Add support for SAW regulators
Date: Tue, 9 Feb 2016 15:21:54 -0700	[thread overview]
Message-ID: <20160209222154.GB1646@linaro.org> (raw)
In-Reply-To: <1455023549-30836-1-git-send-email-georgi.djakov@linaro.org>

On Tue, Feb 09 2016 at 06:13 -0700, Georgi Djakov wrote:
>The SAW (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper)
>is part of the SPM subsystem. It is a hardware block in the Qualcomm
>chipsets that regulates the power to the CPU cores on platform such as
>apq8064, msm8974, apq8084 and others.
>
>Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
>---
>
>Changes since v3 (https://lkml.org/lkml/2016/2/3/829)
> * Add MFD dependency to Kconfig
> * Rename SAW2 to SAW as we may support other SAW generations than just 2
> * Increase timeout to 100us
>
>Changes since v2 (https://lkml.org/lkml/2016/1/28/481)
> * Address the comments from Mark. Thanks!
> - Implement regulator_get_voltage_sel() instead of regulator_get_voltage()
> - Add cpu_relax() in the loop
> - Specify ramp_delay
> - Drop the legacy "regulator-name" property
>
>Changes since v1 (https://lkml.org/lkml/2015/12/18/629)
> * Move into a separate regulator driver
>
> .../bindings/regulator/qcom,saw-regulator.txt      |   31 +++
> drivers/regulator/Kconfig                          |   12 +
> drivers/regulator/Makefile                         |    1 +
> drivers/regulator/qcom_saw-regulator.c             |  229 ++++++++++++++++++++
> 4 files changed, 273 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
> create mode 100644 drivers/regulator/qcom_saw-regulator.c
>
>diff --git a/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
>new file mode 100644
>index 000000000000..977fec08b2ae
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
>@@ -0,0 +1,31 @@
>+Qualcomm SAW Regulators
>+
>+SAW (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper) is a hardware
>+block in the Qualcomm chipsets that regulates the power to the CPU cores on devices
>+such as APQ8064, MSM8974, APQ8084 and others.
>+
>+- compatible:
>+	Usage: required
>+	Value type: <string>
>+	Definition: must be one of:
>+			"qcom,apq8064-saw2-v1.1-regulator"
>+
>+Example:
>+                saw0: power-controller@2089000 {
>+			compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
>+			reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
>+			#address-cells = <1>;
>+			#size-cells = <1>;
>+
>+			saw0_regulator: regulator@2089000 {
>+				compatible = "qcom,apq8064-saw2-v1.1-regulator";
>+				regulator-always-on;
>+				regulator-min-microvolt = <825000>;
>+				regulator-max-microvolt = <1250000>;
>+			};
>+		};
>+
>+
>+		&CPU0 {
>+			cpu-supply = <&saw0_regulator>;
>+		};
>diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
>index 74a6354eaefa..6d5f4fce1d75 100644
>--- a/drivers/regulator/Kconfig
>+++ b/drivers/regulator/Kconfig
>@@ -558,6 +558,18 @@ config REGULATOR_QCOM_RPM
> 	  Qualcomm RPM as a module. The module will be named
> 	  "qcom_rpm-regulator".
>
>+config REGULATOR_QCOM_SAW
>+	tristate "Qualcomm SAW regulator driver"
>+	depends on (ARCH_QCOM || COMPILE_TEST) && MFD_SYSCON
>+	help
>+	  If you say yes to this option, support will be included for the
>+	  regulators providing power to the CPU cores on devices such as
>+	  APQ8064.
>+
>+	  Say M here if you want to include support for the CPU core voltage
>+	  regulators as a module. The module will be named
>+	  "qcom_saw-regulator".
>+
> config REGULATOR_QCOM_SMD_RPM
> 	tristate "Qualcomm SMD based RPM regulator driver"
> 	depends on QCOM_SMD_RPM
>diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
>index 348cfd727350..75a0b4a8f1b2 100644
>--- a/drivers/regulator/Makefile
>+++ b/drivers/regulator/Makefile
>@@ -64,6 +64,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
> obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
> obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
>+obj-$(CONFIG_REGULATOR_QCOM_SAW)+= qcom_saw-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
> obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
>diff --git a/drivers/regulator/qcom_saw-regulator.c b/drivers/regulator/qcom_saw-regulator.c
>new file mode 100644
>index 000000000000..c800f16adaf0
>--- /dev/null
>+++ b/drivers/regulator/qcom_saw-regulator.c
>@@ -0,0 +1,229 @@
>+/*
>+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 and
>+ * only version 2 as published by the Free Software Foundation.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+ * GNU General Public License for more details.
>+ */
>+
>+#include <linux/delay.h>
>+#include <linux/kernel.h>
>+#include <linux/mfd/syscon.h>
>+#include <linux/module.h>
>+#include <linux/of.h>
>+#include <linux/of_platform.h>
>+#include <linux/platform_device.h>
>+#include <linux/regmap.h>
>+#include <linux/regulator/driver.h>
>+#include <linux/regulator/of_regulator.h>
>+
>+#define	SPM_REG_STS_1			0x10
>+#define	SPM_REG_VCTL			0x14
>+#define	SPM_REG_PMIC_DATA_0		0x28
>+#define	SPM_REG_PMIC_DATA_1		0x2c
>+#define	SPM_REG_RST			0x30
>+
These register offsets are SoC specific. You may want to follow the model
of drivers/soc/qcom/spm.c in getting register offsets.

While I see that you are only supporting APQ8064 with this patch, you
probably would want to think a bit far ahead. To support any other QCOM
SoC, you would need extensive changes.

>+struct saw_vreg {
>+	struct device		*dev;
>+	struct regmap		*regmap;
>+	struct regulator_desc	rdesc;
>+	struct regulator_dev	*rdev;
>+	unsigned int		sel;
>+};
>+
>+struct spm_vlevel_data {
>+	struct saw_vreg *vreg;
>+	unsigned int sel;
>+};
>+
>+static int saw_regulator_get_voltage_sel(struct regulator_dev *rdev)
>+{
>+	struct saw_vreg *vreg = rdev_get_drvdata(rdev);
>+
>+	return vreg->sel;
>+}
>+
>+static void smp_set_vdd(void *data)
>+{
>+	struct spm_vlevel_data *vdata = (struct spm_vlevel_data *)data;
>+	struct saw_vreg *vreg = vdata->vreg;
>+	unsigned long new_sel = vdata->sel;
>+	u32 val, new_val;
>+	u32 vctl, data0, data1;
>+	unsigned long timeout;
>+
>+	if (vreg->sel == new_sel)
>+		return;
>+
>+	regmap_read(vreg->regmap, SPM_REG_VCTL, &vctl);
>+	regmap_read(vreg->regmap, SPM_REG_PMIC_DATA_0, &data0);
>+	regmap_read(vreg->regmap, SPM_REG_PMIC_DATA_1, &data1);
>+
>+	/* select the band */
>+	val = 0x80 | new_sel;
>+
>+	vctl &= ~0xff;
>+	vctl |= val;
>+
>+	data0 &= ~0xff;
>+	data0 |= val;
>+
>+	data1 &= ~0x3f;
>+	data1 |= val & 0x3f;
>+	data1 &= ~0x3f0000;
>+	data1 |= ((val & 0x3f) << 16);
>+
>+	regmap_write(vreg->regmap, SPM_REG_RST, 1);
>+	regmap_write(vreg->regmap, SPM_REG_VCTL, vctl);
>+	regmap_write(vreg->regmap, SPM_REG_PMIC_DATA_0, data0);
>+	regmap_write(vreg->regmap, SPM_REG_PMIC_DATA_1, data1);
>+
>+	timeout = jiffies + usecs_to_jiffies(100);
>+	do {
>+		regmap_read(vreg->regmap, SPM_REG_STS_1, &new_val);
>+		new_val &= 0xff;
>+		if (new_val == val) {
>+			vreg->sel = new_sel;
>+			return;
>+		}
>+
>+		cpu_relax();
>+
>+	} while (time_before(jiffies, timeout));
>+
>+	pr_err("%s: Voltage not changed: %#x\n", __func__, new_val);
>+}
>+
>+static int saw_regulator_set_voltage_sel(struct regulator_dev *rdev,
>+					 unsigned selector)
>+{
>+	struct saw_vreg *vreg = rdev_get_drvdata(rdev);
>+	struct spm_vlevel_data data;
>+	int cpu = rdev_get_id(rdev);
>+
>+	data.vreg = vreg;
>+	data.sel = selector;
>+
>+	return smp_call_function_single(cpu, smp_set_vdd, &data, true);
>+}
>+
>+static struct regulator_ops saw_regulator_ops = {
>+	.list_voltage = regulator_list_voltage_linear_range,
>+	.set_voltage_sel = saw_regulator_set_voltage_sel,
>+	.get_voltage_sel = saw_regulator_get_voltage_sel,
>+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
>+};
>+
>+static struct regulator_desc saw_regulator = {
>+	.owner = THIS_MODULE,
>+	.type = REGULATOR_VOLTAGE,
>+	.ops  = &saw_regulator_ops,
>+	.linear_ranges = (struct regulator_linear_range[]) {
>+		REGULATOR_LINEAR_RANGE(700000, 0, 56, 12500),
>+	},
>+	.n_linear_ranges = 1,
>+	.n_voltages = 57,
>+	.ramp_delay = 1250,
>+};
>+
>+static struct saw_vreg *saw_get_drv(struct platform_device *pdev,
>+				    int *vreg_cpu)
>+{
>+	struct saw_vreg *vreg = NULL;
>+	struct device_node *cpu_node, *saw_node;
>+	int cpu;
>+	bool found;
>+
>+	for_each_possible_cpu(cpu) {
>+		cpu_node = of_cpu_device_node_get(cpu);
>+		if (!cpu_node)
>+			continue;
>+		saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
>+		found = (saw_node == pdev->dev.of_node->parent);
>+		of_node_put(saw_node);
>+		of_node_put(cpu_node);
>+		if (found)
>+			break;
>+	}
>+
>+	if (found) {
>+		vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
>+		if (vreg)
>+			*vreg_cpu = cpu;
>+	}
>+
>+	return vreg;
>+}
>+
>+static const struct of_device_id qcom_saw_regulator_match[] = {
>+	{ .compatible = "qcom,apq8064-saw2-v1.1-regulator" },
>+	{ }
>+};
>+MODULE_DEVICE_TABLE(of, qcom_saw_regulator_match);
>+
>+static int qcom_saw_regulator_probe(struct platform_device *pdev)
>+{
>+	struct device *dev = &pdev->dev;
>+	struct device_node *np = dev->of_node;
>+	struct device_node *saw_np;
>+	struct saw_vreg *vreg;
>+	struct regulator_config config = { };
>+	int ret = 0, cpu = 0;
>+	char name[] = "kraitXX";
>+
>+	vreg = saw_get_drv(pdev, &cpu);
>+	if (!vreg)
>+		return -EINVAL;
>+
>+	saw_np = of_get_parent(np);
>+	if (!saw_np)
>+		return -ENODEV;
>+
>+	vreg->regmap = syscon_node_to_regmap(saw_np);
>+	of_node_put(saw_np);
>+	if (IS_ERR(config.regmap))
>+		return PTR_ERR(config.regmap);
>+
>+	snprintf(name, sizeof(name), "krait%d", cpu);
>+
>+	config.regmap = vreg->regmap;
>+	config.dev = &pdev->dev;
>+	config.of_node = np;
>+	config.driver_data = vreg;
>+
>+	vreg->rdesc = saw_regulator;
>+	vreg->rdesc.id = cpu;
>+	vreg->rdesc.name = name;
>+	config.init_data = of_get_regulator_init_data(&pdev->dev,
>+						      pdev->dev.of_node,
>+						      &vreg->rdesc);
>+
>+	vreg->rdev = devm_regulator_register(&pdev->dev, &vreg->rdesc, &config);
>+	if (IS_ERR(vreg->rdev)) {
>+		ret = PTR_ERR(vreg->rdev);
>+		dev_err(dev, "failed to register SAW regulator: %d\n", ret);
>+		return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+static struct platform_driver qcom_saw_regulator_driver = {
>+	.driver = {
>+		.name = "qcom-saw-regulator",
>+		.of_match_table = qcom_saw_regulator_match,
>+	},
>+	.probe = qcom_saw_regulator_probe,
>+};
>+
>+module_platform_driver(qcom_saw_regulator_driver);
>+
builtin_platform_driver() perhaps ?

>+MODULE_ALIAS("platform:qcom-saw-regulator");
>+MODULE_DESCRIPTION("Qualcomm SAW regulator driver");
>+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
>+MODULE_LICENSE("GPL v2");

  parent reply	other threads:[~2016-02-09 22:21 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-09 13:12 [PATCH v4] regulator: qcom-saw: Add support for SAW regulators Georgi Djakov
2016-02-09 18:20 ` Applied "regulator: qcom-saw: Add support for SAW regulators" to the regulator tree Mark Brown
2016-02-09 22:21 ` Lina Iyer [this message]
2016-02-10 10:13   ` [PATCH v4] regulator: qcom-saw: Add support for SAW regulators Mark Brown
2016-02-10 16:42     ` Lina Iyer
2016-02-10 18:54       ` Mark Brown
2016-02-10 12:52   ` Georgi Djakov
2016-02-10 18:36     ` Stephen Boyd
2016-02-10 18:43       ` Mark Brown
2016-02-10 19:04         ` Stephen Boyd
2016-02-10 19:21           ` Mark Brown
2016-02-10 22:46             ` Stephen Boyd
2016-02-11 10:17               ` Georgi Djakov
2016-02-12  0:17                 ` Stephen Boyd
2016-02-12 23:03                   ` Mark Brown
2016-02-19 16:07 ` Mark Brown
2016-03-15  9:29 ` Applied "regulator: qcom-saw: Add support for SAW regulators" to the regulator tree Mark Brown
2016-03-15  9:30   ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160209222154.GB1646@linaro.org \
    --to=lina.iyer@linaro.org \
    --cc=andy.gross@linaro.org \
    --cc=broonie@kernel.org \
    --cc=georgi.djakov@linaro.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sboyd@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.