All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Ribeiro <drwyrm@gmail.com>
To: Mark Brown <broonie@sirena.org.uk>,
	Liam Girdwood <lrg@slimlogic.co.uk>,
	linux-kernel <linux-kernel@vger.kernel.org>
Cc: Eric Miao <eric.y.miao@gmail.com>,
	David Brownell <david-b@pacbell.net>,
	Pierre Ossman <pierre@ossman.eu>,
	openezx-devel <openezx-devel@lists.openezx.org>,
	linux-arm-kernel <linux-arm-kernel@lists.arm.linux.org.uk>
Subject: [PATCHv2 2/2] PCAP regulator driver (for 2.6.32)
Date: Fri, 26 Jun 2009 20:08:41 -0300	[thread overview]
Message-ID: <1246057721.10360.318.camel@brutus> (raw)

[-- Attachment #1: Type: text/plain, Size: 10481 bytes --]

Changed: Removed workaround for regulator use_count issues.

=== CUT HERE ===
Add (partial) support for the voltage regulators on the PCAP2 PMIC.

Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>

---
 drivers/regulator/Kconfig          |    7 +
 drivers/regulator/Makefile         |    1 +
 drivers/regulator/pcap-regulator.c |  329 ++++++++++++++++++++++++++++++++++++
 3 files changed, 337 insertions(+), 0 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f431779..da7483e 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -117,4 +117,11 @@ config REGULATOR_LP3971
 	 Say Y here to support the voltage regulators and convertors
 	 on National Semiconductors LP3971 PMIC
 
+config REGULATOR_PCAP
+	tristate "PCAP2 regulator driver"
+	depends on EZX_PCAP
+	help
+	 This driver provides support for the voltage regulators of the
+	 PCAP2 PMIC.
+
 endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4d762c4..3a9748f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
new file mode 100644
index 0000000..7ebaa6a
--- /dev/null
+++ b/drivers/regulator/pcap-regulator.c
@@ -0,0 +1,329 @@
+/*
+ * PCAP2 Regulator Driver
+ *
+ * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ezx-pcap.h>
+
+static const u16 V1_table[] = {
+	2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+};
+
+static const u16 V2_table[] = {
+	2500, 2775,
+};
+
+static const u16 V3_table[] = {
+	1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+};
+
+static const u16 V4_table[] = {
+	1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+};
+
+static const u16 V5_table[] = {
+	1875, 2275, 2475, 2775,
+};
+
+static const u16 V6_table[] = {
+	2475, 2775,
+};
+
+static const u16 V7_table[] = {
+	1875, 2775,
+};
+
+#define V8_table V4_table
+
+static const u16 V9_table[] = {
+	1575, 1875, 2475, 2775,
+};
+
+static const u16 V10_table[] = {
+	5000,
+};
+
+static const u16 VAUX1_table[] = {
+	1875, 2475, 2775, 3000,
+};
+
+#define VAUX2_table VAUX1_table
+
+static const u16 VAUX3_table[] = {
+	1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
+	2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+};
+
+static const u16 VAUX4_table[] = {
+	1800, 1800, 3000, 5000,
+};
+
+static const u16 VSIM_table[] = {
+	1875, 3000,
+};
+
+static const u16 VSIM2_table[] = {
+	1875,
+};
+
+static const u16 VVIB_table[] = {
+	1300, 1800, 2000, 3000,
+};
+
+static const u16 SW1_table[] = {
+	900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
+	1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+};
+
+#define SW2_table SW1_table
+
+static const u16 SW3_table[] = {
+	4000, 4500, 5000, 5500,
+};
+
+struct pcap_regulator {
+	const u8 reg;
+	const u8 en;
+	const u8 index;
+	const u8 stby;
+	const u8 lowpwr;
+	const u8 n_voltages;
+	const u16 *voltage_table;
+};
+
+#define NA 0xff
+
+#define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr)		\
+	[_vreg]	= {							\
+		.reg		= _reg,					\
+		.en		= _en,					\
+		.index		= _index,				\
+		.stby		= _stby,				\
+		.lowpwr		= _lowpwr,				\
+		.n_voltages	= ARRAY_SIZE(_vreg##_table),		\
+		.voltage_table	= _vreg##_table,			\
+	}
+
+static struct pcap_regulator vreg_table[] = {
+	VREG_INFO(V1,    PCAP_REG_VREG1,   1,  2,  18, 0),
+	VREG_INFO(V2,    PCAP_REG_VREG1,   5,  6,  19, 22),
+	VREG_INFO(V3,    PCAP_REG_VREG1,   7,  8,  20, 23),
+	VREG_INFO(V4,    PCAP_REG_VREG1,   11, 12, 21, 24),
+	/* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */
+	VREG_INFO(V5,    PCAP_REG_VREG1,   15, 16, 12, 19),
+
+	VREG_INFO(V6,    PCAP_REG_VREG2,   1,  2,  14, 20),
+	VREG_INFO(V7,    PCAP_REG_VREG2,   3,  4,  15, 21),
+	VREG_INFO(V8,    PCAP_REG_VREG2,   5,  6,  16, 22),
+	VREG_INFO(V9,    PCAP_REG_VREG2,   9,  10, 17, 23),
+	VREG_INFO(V10,   PCAP_REG_VREG2,   10, NA, 18, 24),
+
+	VREG_INFO(VAUX1, PCAP_REG_AUXVREG, 1,  2,  22, 23),
+	/* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */
+	VREG_INFO(VAUX2, PCAP_REG_AUXVREG, 4,  5,  0,  1),
+	VREG_INFO(VAUX3, PCAP_REG_AUXVREG, 7,  8,  2,  3),
+	VREG_INFO(VAUX4, PCAP_REG_AUXVREG, 12, 13, 4,  5),
+	VREG_INFO(VSIM,  PCAP_REG_AUXVREG, 17, 18, NA, 6),
+	VREG_INFO(VSIM2, PCAP_REG_AUXVREG, 16, NA, NA, 7),
+	VREG_INFO(VVIB,  PCAP_REG_AUXVREG, 19, 20, NA, NA),
+
+	VREG_INFO(SW1,   PCAP_REG_SWCTRL,  1,  2,  NA, NA),
+	VREG_INFO(SW2,   PCAP_REG_SWCTRL,  6,  7,  NA, NA),
+	/* SW3 STBY is on PCAP_REG_AUXVREG */
+	VREG_INFO(SW3,   PCAP_REG_SWCTRL,  11, 12, 24, NA),
+
+	/* SWxS used to control SWx voltage on standby */
+/*	VREG_INFO(SW1S,  PCAP_REG_LOWPWR,  NA, 12, NA, NA),
+	VREG_INFO(SW2S,  PCAP_REG_LOWPWR,  NA, 20, NA, NA), */
+};
+
+static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
+						int min_uV, int max_uV)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	int uV;
+	u32 tmp;
+	u8 i;
+
+	if (vreg->n_voltages == 1)
+		return -EINVAL;
+
+	for (i = 0; i < vreg->n_voltages; i++) {
+		/* For V1 the first is not the best match */
+		if (i == 0 && rdev_get_id(rdev) == V1)
+			i = 1;
+		else if (i + 1 == vreg->n_voltages && rdev_get_id(rdev) == V1)
+			i = 0;
+
+		uV = vreg->voltage_table[i] * 1000;
+		if (min_uV <= uV && uV <= max_uV) {
+			ezx_pcap_read(pcap, vreg->reg, &tmp);
+			tmp &= ~((vreg->n_voltages - 1) << vreg->index);
+			tmp |= i << vreg->index;
+			ezx_pcap_write(pcap, vreg->reg, tmp);
+			return 0;
+		}
+		if (i == 0 && rdev_get_id(rdev) == V1)
+			i = vreg->n_voltages - 1;
+	}
+
+	return -EINVAL;
+}
+
+static int pcap_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+	int mV;
+
+	if (vreg->n_voltages == 1)
+		return vreg->voltage_table[0] * 1000;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+	mV = vreg->voltage_table[tmp];
+
+	return mV * 1000;
+}
+
+static int pcap_regulator_enable(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	tmp |= (1 << vreg->en);
+	ezx_pcap_write(pcap, vreg->reg, tmp);
+
+	return 0;
+}
+
+static int pcap_regulator_disable(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	tmp &= ~(1 << vreg->en);
+	ezx_pcap_write(pcap, vreg->reg, tmp);
+
+	return 0;
+}
+
+static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	return (tmp >> vreg->en) & 1;
+}
+
+static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
+							unsigned int index)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+
+	return vreg->voltage_table[index] * 1000;
+}
+
+static struct regulator_ops pcap_regulator_ops = {
+	.list_voltage	= pcap_regulator_list_voltage,
+	.set_voltage	= pcap_regulator_set_voltage,
+	.get_voltage	= pcap_regulator_get_voltage,
+	.enable		= pcap_regulator_enable,
+	.disable	= pcap_regulator_disable,
+	.is_enabled	= pcap_regulator_is_enabled,
+};
+
+#define VREG(_vreg)						\
+	[_vreg]	= {						\
+		.name		= #_vreg,			\
+		.id		= _vreg,			\
+		.n_voltages	= ARRAY_SIZE(_vreg##_table),	\
+		.ops		= &pcap_regulator_ops,		\
+		.type		= REGULATOR_VOLTAGE,		\
+		.owner		= THIS_MODULE,			\
+	}
+
+static struct regulator_desc pcap_regulators[] = {
+	VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7),
+	VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3),
+	VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2),
+};
+
+static int __devinit pcap_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+	void *pcap = platform_get_drvdata(pdev);
+
+	rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
+				pdev->dev.platform_data, pcap);
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit pcap_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver pcap_regulator_driver = {
+	.driver = {
+		.name = "pcap-regulator",
+	},
+	.probe = pcap_regulator_probe,
+	.remove = __devexit_p(pcap_regulator_remove),
+};
+
+static int __init pcap_regulator_init(void)
+{
+	return platform_driver_register(&pcap_regulator_driver);
+}
+
+static void __exit pcap_regulator_exit(void)
+{
+	platform_driver_unregister(&pcap_regulator_driver);
+}
+
+module_init(pcap_regulator_init);
+module_exit(pcap_regulator_exit);
+
+MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>");
+MODULE_DESCRIPTION("PCAP2 Regulator Driver");
+MODULE_LICENSE("GPL");
-- 
tg: (69e76aa..) ezx/pcap_regulator (depends on: ezx/local/pcap)

-- 
Daniel Ribeiro

[-- Attachment #2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

             reply	other threads:[~2009-06-26 23:09 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-26 23:08 Daniel Ribeiro [this message]
2009-06-27  1:04 ` [PATCHv2 2/2] PCAP regulator driver (for 2.6.32) Mark Brown
2009-06-27  2:14   ` Daniel Ribeiro

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=1246057721.10360.318.camel@brutus \
    --to=drwyrm@gmail.com \
    --cc=broonie@sirena.org.uk \
    --cc=david-b@pacbell.net \
    --cc=eric.y.miao@gmail.com \
    --cc=linux-arm-kernel@lists.arm.linux.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lrg@slimlogic.co.uk \
    --cc=openezx-devel@lists.openezx.org \
    --cc=pierre@ossman.eu \
    /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.