All of lore.kernel.org
 help / color / mirror / Atom feed
From: cy_huang <u0084500@gmail.com>
To: lgirdwood@gmail.com, broonie@kernel.org, robh+dt@kernel.org
Cc: cy_huang@richtek.com, gene_chen@richtek.com,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
Subject: [PATCH 1/2] regulator: rt4801: Add support for RT4801 Display Bias regulator driver
Date: Fri, 14 Aug 2020 23:27:03 +0800	[thread overview]
Message-ID: <1597418824-15906-1-git-send-email-u0084500@gmail.com> (raw)

From: ChiYuan Huang <cy_huang@richtek.com>

Adds support for the RT4801 DSV. It has two regulators (DSVP/DSVN) with
an I2C interface. DSVP/DSVN can provide the display panel module for the
positive/negative voltage range from (+/-)4V to (+/-)6V.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---
 drivers/regulator/Kconfig            |   7 ++
 drivers/regulator/Makefile           |   1 +
 drivers/regulator/rt4801-regulator.c | 223 +++++++++++++++++++++++++++++++++++
 3 files changed, 231 insertions(+)
 create mode 100644 drivers/regulator/rt4801-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index de17ef7..2786f11 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -894,6 +894,13 @@ config REGULATOR_RN5T618
 config REGULATOR_ROHM
 	tristate
 
+config REGULATOR_RT4801
+	tristate "Richtek RT4801 Regulators"
+	depends on I2C
+	help
+	  This adds support for voltage regulators in Richtek RT4801 Display Bias IC.
+	  The device supports two regulators (DSVP/DSVN).
+
 config REGULATOR_RT5033
 	tristate "Richtek RT5033 Regulators"
 	depends on MFD_RT5033
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d8d3ecf..d091e52d 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -111,6 +111,7 @@ obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_RK808)   += rk808-regulator.o
 obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
 obj-$(CONFIG_REGULATOR_ROHM)	+= rohm-regulator.o
+obj-$(CONFIG_REGULATOR_RT4801)	+= rt4801-regulator.o
 obj-$(CONFIG_REGULATOR_RT5033)	+= rt5033-regulator.o
 obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
diff --git a/drivers/regulator/rt4801-regulator.c b/drivers/regulator/rt4801-regulator.c
new file mode 100644
index 00000000..0ddc670
--- /dev/null
+++ b/drivers/regulator/rt4801-regulator.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+#define RT4801_REG_VOP	0x00
+#define RT4801_REG_VON	0x01
+#define RT4801_REG_APPS	0x03
+
+#define VOUT_MASK	0x1F
+
+#define MIN_UV		4000000
+#define STEP_UV		100000
+#define MAX_UV		6000000
+#define N_VOLTAGES	((MAX_UV - MIN_UV) / STEP_UV + 1)
+
+#define DSV_OUT_POS	0
+#define DSV_OUT_NEG	1
+#define DSV_OUT_MAX	2
+
+#define DSVP_ENABLE	BIT(0)
+#define DSVN_ENABLE	BIT(1)
+#define DSVALL_ENABLE	(DSVP_ENABLE | DSVN_ENABLE)
+
+struct rt4801_priv {
+	struct device *dev;
+	struct gpio_descs *enable_gpios;
+	unsigned int enable_flag;
+	unsigned int volt_sel[DSV_OUT_MAX];
+};
+
+static int rt4801_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev), ret;
+
+	if (priv->enable_flag & BIT(id)) {
+		ret = regulator_set_voltage_sel_regmap(rdev, selector);
+		if (ret)
+			return ret;
+	}
+
+	priv->volt_sel[id] = selector;
+	return 0;
+}
+
+static int rt4801_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+
+	if (priv->enable_flag & BIT(id))
+		return regulator_get_voltage_sel_regmap(rdev);
+
+	return priv->volt_sel[id];
+}
+
+static int rt4801_enable(struct regulator_dev *rdev)
+{
+	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
+	struct gpio_descs *gpios = priv->enable_gpios;
+	int id = rdev_get_id(rdev), ret;
+
+	if (gpios->ndescs <= id) {
+		dev_warn(&rdev->dev, "no dedicated gpio can control\n");
+		goto bypass_gpio;
+	}
+
+	gpiod_set_value(gpios->desc[id], 1);
+
+bypass_gpio:
+	ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, priv->volt_sel[id]);
+	if (ret)
+		return ret;
+
+	priv->enable_flag |= BIT(id);
+	return 0;
+}
+
+static int rt4801_disable(struct regulator_dev *rdev)
+{
+	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
+	struct gpio_descs *gpios = priv->enable_gpios;
+	int id = rdev_get_id(rdev);
+
+	if (gpios->ndescs <= id) {
+		dev_warn(&rdev->dev, "no dedicated gpio can control\n");
+		goto bypass_gpio;
+	}
+
+	gpiod_set_value(gpios->desc[id], 0);
+
+bypass_gpio:
+	priv->enable_flag &= ~BIT(id);
+	return 0;
+}
+
+static int rt4801_is_enabled(struct regulator_dev *rdev)
+{
+	struct rt4801_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+
+	return !!(priv->enable_flag & BIT(id));
+}
+
+static const struct regulator_ops rt4801_regulator_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = rt4801_set_voltage_sel,
+	.get_voltage_sel = rt4801_get_voltage_sel,
+	.enable = rt4801_enable,
+	.disable = rt4801_disable,
+	.is_enabled = rt4801_is_enabled,
+};
+
+static const struct regulator_desc rt4801_regulator_descs[] = {
+	{
+		.name = "DSVP",
+		.ops = &rt4801_regulator_ops,
+		.of_match = of_match_ptr("DSVP"),
+		.type = REGULATOR_VOLTAGE,
+		.id = DSV_OUT_POS,
+		.min_uV = MIN_UV,
+		.uV_step = STEP_UV,
+		.n_voltages = N_VOLTAGES,
+		.owner = THIS_MODULE,
+		.vsel_reg = RT4801_REG_VOP,
+		.vsel_mask = VOUT_MASK,
+	},
+	{
+		.name = "DSVN",
+		.ops = &rt4801_regulator_ops,
+		.of_match = of_match_ptr("DSVN"),
+		.type = REGULATOR_VOLTAGE,
+		.id = DSV_OUT_NEG,
+		.min_uV = MIN_UV,
+		.uV_step = STEP_UV,
+		.n_voltages = N_VOLTAGES,
+		.owner = THIS_MODULE,
+		.vsel_reg = RT4801_REG_VON,
+		.vsel_mask = VOUT_MASK,
+	},
+};
+
+static const struct regmap_config rt4801_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = RT4801_REG_APPS,
+};
+
+static int rt4801_probe(struct i2c_client *i2c)
+{
+	struct rt4801_priv *priv;
+	struct regmap *regmap;
+	int i;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &i2c->dev;
+	/* bootloader will on, driver only reconfigure enable to all output high */
+	priv->enable_flag = DSVALL_ENABLE;
+
+	regmap = devm_regmap_init_i2c(i2c, &rt4801_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&i2c->dev, "Failed to init regmap\n");
+		return PTR_ERR(regmap);
+	}
+
+	priv->enable_gpios = devm_gpiod_get_array_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->enable_gpios)) {
+		dev_err(&i2c->dev, "Failed to get gpios\n");
+		return PTR_ERR(priv->enable_gpios);
+	}
+
+	for (i = 0; i < DSV_OUT_MAX; i++) {
+		const struct regulator_desc *desc = rt4801_regulator_descs + i;
+		struct regulator_config config = { .dev = &i2c->dev, .driver_data = priv,
+						   .regmap = regmap, };
+		struct regulator_dev *rdev;
+		unsigned int val;
+		int ret;
+
+		/* initialize volt_sel variable */
+		ret = regmap_read(regmap, desc->vsel_reg, &val);
+		if (ret)
+			return ret;
+
+		priv->volt_sel[i] = val & desc->vsel_mask;
+
+		rdev = devm_regulator_register(&i2c->dev, desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&i2c->dev, "Failed to register [%d] regulator\n", i);
+			return PTR_ERR(rdev);
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id rt4801_of_id[] = {
+	{ .compatible = "richtek,rt4801", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rt4801_of_id);
+
+static struct i2c_driver rt4801_driver = {
+	.driver = {
+		.name = "rt4801",
+		.of_match_table = of_match_ptr(rt4801_of_id),
+	},
+	.probe_new = rt4801_probe,
+};
+module_i2c_driver(rt4801_driver);
+
+MODULE_AUTHOR("ChiYuan Hwang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT4801 Display Bias Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


             reply	other threads:[~2020-08-14 15:27 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-14 15:27 cy_huang [this message]
2020-08-14 15:27 ` [PATCH 2/2] regulator: rt4801: Add DT binding documentation cy_huang
2020-08-14 20:35   ` Rob Herring
2020-08-18 16:56 ` [PATCH 1/2] regulator: rt4801: Add support for RT4801 Display Bias regulator driver Mark Brown
2020-08-19 10:01   ` 啟原黃

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=1597418824-15906-1-git-send-email-u0084500@gmail.com \
    --to=u0084500@gmail.com \
    --cc=broonie@kernel.org \
    --cc=cy_huang@richtek.com \
    --cc=devicetree@vger.kernel.org \
    --cc=gene_chen@richtek.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh+dt@kernel.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.