linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Initial support for XPowers AXP288 PMIC
@ 2014-09-08 22:24 Jacob Pan
  2014-09-08 22:24 ` [PATCH 1/4] mfd/axp20x: rename files to support more devices Jacob Pan
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Jacob Pan @ 2014-09-08 22:24 UTC (permalink / raw)
  To: IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Aaron Lu, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson, Jacob Pan

XPowers AXP288 is a customized PMIC found on some Intel Baytrail-CR platforms.
It comes with sub-functions such as USB charging, fuel gauge, ADC, and many LDO
and BUCK channels.

By extending the existing AXP20x driver, this patchset adds basic support
for AXP288 PMIC with GPADC as one MFD cell device driver. It also adds hooks
for ACPI opregion handler driver which can be used to handle ACPI requests.

Currently, the PMIC driver in this patchset does not support platform data
enumeration. But when ACPI _DSD and unified device properties become available,
cell devices with platform data will be added.

This patch does not use intel_soc_pmic core for i2c and regmap handling in that
axp288 shares similar programming interface with other Xpower PMICs supported in
axp20x.c. Therefore, extending axp20x.c to include axp288 makes more sense.


Jacob Pan (4):
  mfd/axp20x: rename files to support more devices
  mfd/axp2xx: extend axp20x to support axp288 pmic
  regulator/axp20x: use axp2xx consolidated header
  iio/adc/axp288: add support for axp288 gpadc

 drivers/iio/adc/Kconfig              |   8 +
 drivers/iio/adc/Makefile             |   1 +
 drivers/iio/adc/axp288_gpadc.c       | 250 ++++++++++++++++++
 drivers/mfd/Kconfig                  |   7 +-
 drivers/mfd/Makefile                 |   2 +-
 drivers/mfd/axp20x.c                 | 258 ------------------
 drivers/mfd/axp2xx.c                 | 500 +++++++++++++++++++++++++++++++++++
 drivers/regulator/axp20x-regulator.c |   6 +-
 include/linux/mfd/axp20x.h           | 180 -------------
 include/linux/mfd/axp2xx.h           | 235 ++++++++++++++++
 10 files changed, 1002 insertions(+), 445 deletions(-)
 create mode 100644 drivers/iio/adc/axp288_gpadc.c
 delete mode 100644 drivers/mfd/axp20x.c
 create mode 100644 drivers/mfd/axp2xx.c
 delete mode 100644 include/linux/mfd/axp20x.h
 create mode 100644 include/linux/mfd/axp2xx.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/4] mfd/axp20x: rename files to support more devices
  2014-09-08 22:24 [PATCH 0/4] Initial support for XPowers AXP288 PMIC Jacob Pan
@ 2014-09-08 22:24 ` Jacob Pan
  2014-09-09  8:11   ` Lee Jones
  2014-09-08 22:24 ` [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic Jacob Pan
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-08 22:24 UTC (permalink / raw)
  To: IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Aaron Lu, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson, Jacob Pan

More XPowers PMIC devices can be supported by extending this driver, so
rename it to axp2xx to cover axp288 variant.

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 drivers/mfd/Kconfig        |   7 +-
 drivers/mfd/Makefile       |   2 +-
 drivers/mfd/axp20x.c       | 258 ---------------------------------------------
 drivers/mfd/axp2xx.c       | 258 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/axp20x.h | 180 -------------------------------
 include/linux/mfd/axp2xx.h | 180 +++++++++++++++++++++++++++++++
 6 files changed, 443 insertions(+), 442 deletions(-)
 delete mode 100644 drivers/mfd/axp20x.c
 create mode 100644 drivers/mfd/axp2xx.c
 delete mode 100644 include/linux/mfd/axp20x.h
 create mode 100644 include/linux/mfd/axp2xx.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index de5abf2..42a70a3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -67,14 +67,15 @@ config MFD_BCM590XX
 	help
 	  Support for the BCM590xx PMUs from Broadcom
 
-config MFD_AXP20X
-	bool "X-Powers AXP20X"
+config MFD_AXP2XX
+	bool "X-Powers AXP2XX"
 	select MFD_CORE
 	select REGMAP_I2C
 	select REGMAP_IRQ
 	depends on I2C=y
 	help
-	  If you say Y here you get support for the X-Powers AXP202 and AXP209.
+	  If you say Y here you get support for the X-Powers AXP202, AXP209 and
+	  AXP288 power management IC (PMIC).
 	  This driver include only the core APIs. You have to select individual
 	  components like regulators or the PEK (Power Enable Key) under the
 	  corresponding menus.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f001487..55d76b3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -103,7 +103,7 @@ obj-$(CONFIG_PMIC_DA9052)	+= da9052-irq.o
 obj-$(CONFIG_PMIC_DA9052)	+= da9052-core.o
 obj-$(CONFIG_MFD_DA9052_SPI)	+= da9052-spi.o
 obj-$(CONFIG_MFD_DA9052_I2C)	+= da9052-i2c.o
-obj-$(CONFIG_MFD_AXP20X)	+= axp20x.o
+obj-$(CONFIG_MFD_AXP2XX)	+= axp2xx.o
 
 obj-$(CONFIG_MFD_LP3943)	+= lp3943.o
 obj-$(CONFIG_MFD_LP8788)	+= lp8788.o lp8788-irq.o
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
deleted file mode 100644
index dee6539..0000000
--- a/drivers/mfd/axp20x.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
- *
- * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
- * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
- * as well as 4 configurable GPIOs.
- *
- * Author: Carlo Caione <carlo@caione.org>
- *
- * 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/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/axp20x.h>
-#include <linux/mfd/core.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-
-#define AXP20X_OFF	0x80
-
-static const struct regmap_range axp20x_writeable_ranges[] = {
-	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
-	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
-};
-
-static const struct regmap_range axp20x_volatile_ranges[] = {
-	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
-};
-
-static const struct regmap_access_table axp20x_writeable_table = {
-	.yes_ranges	= axp20x_writeable_ranges,
-	.n_yes_ranges	= ARRAY_SIZE(axp20x_writeable_ranges),
-};
-
-static const struct regmap_access_table axp20x_volatile_table = {
-	.yes_ranges	= axp20x_volatile_ranges,
-	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
-};
-
-static struct resource axp20x_pek_resources[] = {
-	{
-		.name	= "PEK_DBR",
-		.start	= AXP20X_IRQ_PEK_RIS_EDGE,
-		.end	= AXP20X_IRQ_PEK_RIS_EDGE,
-		.flags	= IORESOURCE_IRQ,
-	}, {
-		.name	= "PEK_DBF",
-		.start	= AXP20X_IRQ_PEK_FAL_EDGE,
-		.end	= AXP20X_IRQ_PEK_FAL_EDGE,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static const struct regmap_config axp20x_regmap_config = {
-	.reg_bits	= 8,
-	.val_bits	= 8,
-	.wr_table	= &axp20x_writeable_table,
-	.volatile_table	= &axp20x_volatile_table,
-	.max_register	= AXP20X_FG_RES,
-	.cache_type	= REGCACHE_RBTREE,
-};
-
-#define AXP20X_IRQ(_irq, _off, _mask) \
-	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
-
-static const struct regmap_irq axp20x_regmap_irqs[] = {
-	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
-	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
-	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
-	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
-	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
-	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
-	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
-	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
-	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
-	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
-	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
-	AXP20X_IRQ(CHARG,		1, 3),
-	AXP20X_IRQ(CHARG_DONE,		1, 2),
-	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
-	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
-	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
-	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
-	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
-	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
-	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
-	AXP20X_IRQ(PEK_SHORT,		2, 1),
-	AXP20X_IRQ(PEK_LONG,		2, 0),
-	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
-	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
-	AXP20X_IRQ(VBUS_VALID,		3, 5),
-	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
-	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
-	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
-	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
-	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
-	AXP20X_IRQ(TIMER,		4, 7),
-	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
-	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
-	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
-	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
-	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
-	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
-};
-
-static const struct of_device_id axp20x_of_match[] = {
-	{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
-	{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, axp20x_of_match);
-
-/*
- * This is useless for OF-enabled devices, but it is needed by I2C subsystem
- */
-static const struct i2c_device_id axp20x_i2c_id[] = {
-	{ },
-};
-MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
-
-static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
-	.name			= "axp20x_irq_chip",
-	.status_base		= AXP20X_IRQ1_STATE,
-	.ack_base		= AXP20X_IRQ1_STATE,
-	.mask_base		= AXP20X_IRQ1_EN,
-	.num_regs		= 5,
-	.irqs			= axp20x_regmap_irqs,
-	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
-	.mask_invert		= true,
-	.init_ack_masked	= true,
-};
-
-static const char * const axp20x_supplies[] = {
-	"acin",
-	"vin2",
-	"vin3",
-	"ldo24in",
-	"ldo3in",
-	"ldo5in",
-};
-
-static struct mfd_cell axp20x_cells[] = {
-	{
-		.name			= "axp20x-pek",
-		.num_resources		= ARRAY_SIZE(axp20x_pek_resources),
-		.resources		= axp20x_pek_resources,
-	}, {
-		.name			= "axp20x-regulator",
-		.parent_supplies	= axp20x_supplies,
-		.num_parent_supplies	= ARRAY_SIZE(axp20x_supplies),
-	},
-};
-
-static struct axp20x_dev *axp20x_pm_power_off;
-static void axp20x_power_off(void)
-{
-	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
-		     AXP20X_OFF);
-}
-
-static int axp20x_i2c_probe(struct i2c_client *i2c,
-			 const struct i2c_device_id *id)
-{
-	struct axp20x_dev *axp20x;
-	const struct of_device_id *of_id;
-	int ret;
-
-	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
-	if (!axp20x)
-		return -ENOMEM;
-
-	of_id = of_match_device(axp20x_of_match, &i2c->dev);
-	if (!of_id) {
-		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
-		return -ENODEV;
-	}
-	axp20x->variant = (long) of_id->data;
-
-	axp20x->i2c_client = i2c;
-	axp20x->dev = &i2c->dev;
-	dev_set_drvdata(axp20x->dev, axp20x);
-
-	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
-	if (IS_ERR(axp20x->regmap)) {
-		ret = PTR_ERR(axp20x->regmap);
-		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
-				  IRQF_ONESHOT | IRQF_SHARED, -1,
-				  &axp20x_regmap_irq_chip,
-				  &axp20x->regmap_irqc);
-	if (ret) {
-		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
-		return ret;
-	}
-
-	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
-			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
-
-	if (ret) {
-		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
-		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
-		return ret;
-	}
-
-	if (!pm_power_off) {
-		axp20x_pm_power_off = axp20x;
-		pm_power_off = axp20x_power_off;
-	}
-
-	dev_info(&i2c->dev, "AXP20X driver loaded\n");
-
-	return 0;
-}
-
-static int axp20x_i2c_remove(struct i2c_client *i2c)
-{
-	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
-
-	if (axp20x == axp20x_pm_power_off) {
-		axp20x_pm_power_off = NULL;
-		pm_power_off = NULL;
-	}
-
-	mfd_remove_devices(axp20x->dev);
-	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
-
-	return 0;
-}
-
-static struct i2c_driver axp20x_i2c_driver = {
-	.driver = {
-		.name	= "axp20x",
-		.owner	= THIS_MODULE,
-		.of_match_table	= of_match_ptr(axp20x_of_match),
-	},
-	.probe		= axp20x_i2c_probe,
-	.remove		= axp20x_i2c_remove,
-	.id_table	= axp20x_i2c_id,
-};
-
-module_i2c_driver(axp20x_i2c_driver);
-
-MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
-MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/axp2xx.c b/drivers/mfd/axp2xx.c
new file mode 100644
index 0000000..c534443
--- /dev/null
+++ b/drivers/mfd/axp2xx.c
@@ -0,0 +1,258 @@
+/*
+ * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ *
+ * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
+ * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as 4 configurable GPIOs.
+ *
+ * Author: Carlo Caione <carlo@caione.org>
+ *
+ * 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/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/axp2xx.h>
+#include <linux/mfd/core.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#define AXP20X_OFF	0x80
+
+static const struct regmap_range axp20x_writeable_ranges[] = {
+	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
+};
+
+static const struct regmap_range axp20x_volatile_ranges[] = {
+	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
+};
+
+static const struct regmap_access_table axp20x_writeable_table = {
+	.yes_ranges	= axp20x_writeable_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(axp20x_writeable_ranges),
+};
+
+static const struct regmap_access_table axp20x_volatile_table = {
+	.yes_ranges	= axp20x_volatile_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
+};
+
+static struct resource axp20x_pek_resources[] = {
+	{
+		.name	= "PEK_DBR",
+		.start	= AXP20X_IRQ_PEK_RIS_EDGE,
+		.end	= AXP20X_IRQ_PEK_RIS_EDGE,
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.name	= "PEK_DBF",
+		.start	= AXP20X_IRQ_PEK_FAL_EDGE,
+		.end	= AXP20X_IRQ_PEK_FAL_EDGE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static const struct regmap_config axp20x_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.wr_table	= &axp20x_writeable_table,
+	.volatile_table	= &axp20x_volatile_table,
+	.max_register	= AXP20X_FG_RES,
+	.cache_type	= REGCACHE_RBTREE,
+};
+
+#define AXP20X_IRQ(_irq, _off, _mask) \
+	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+
+static const struct regmap_irq axp20x_regmap_irqs[] = {
+	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
+	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
+	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
+	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
+	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
+	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
+	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
+	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
+	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
+	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
+	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
+	AXP20X_IRQ(CHARG,		1, 3),
+	AXP20X_IRQ(CHARG_DONE,		1, 2),
+	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
+	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
+	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
+	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
+	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
+	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
+	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
+	AXP20X_IRQ(PEK_SHORT,		2, 1),
+	AXP20X_IRQ(PEK_LONG,		2, 0),
+	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
+	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
+	AXP20X_IRQ(VBUS_VALID,		3, 5),
+	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
+	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
+	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
+	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
+	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
+	AXP20X_IRQ(TIMER,		4, 7),
+	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
+	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
+	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
+	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
+	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
+	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
+};
+
+static const struct of_device_id axp20x_of_match[] = {
+	{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
+	{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, axp20x_of_match);
+
+/*
+ * This is useless for OF-enabled devices, but it is needed by I2C subsystem
+ */
+static const struct i2c_device_id axp20x_i2c_id[] = {
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
+
+static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
+	.name			= "axp20x_irq_chip",
+	.status_base		= AXP20X_IRQ1_STATE,
+	.ack_base		= AXP20X_IRQ1_STATE,
+	.mask_base		= AXP20X_IRQ1_EN,
+	.num_regs		= 5,
+	.irqs			= axp20x_regmap_irqs,
+	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
+	.mask_invert		= true,
+	.init_ack_masked	= true,
+};
+
+static const char * const axp20x_supplies[] = {
+	"acin",
+	"vin2",
+	"vin3",
+	"ldo24in",
+	"ldo3in",
+	"ldo5in",
+};
+
+static struct mfd_cell axp20x_cells[] = {
+	{
+		.name			= "axp20x-pek",
+		.num_resources		= ARRAY_SIZE(axp20x_pek_resources),
+		.resources		= axp20x_pek_resources,
+	}, {
+		.name			= "axp20x-regulator",
+		.parent_supplies	= axp20x_supplies,
+		.num_parent_supplies	= ARRAY_SIZE(axp20x_supplies),
+	},
+};
+
+static struct axp20x_dev *axp20x_pm_power_off;
+static void axp20x_power_off(void)
+{
+	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
+		     AXP20X_OFF);
+}
+
+static int axp20x_i2c_probe(struct i2c_client *i2c,
+			 const struct i2c_device_id *id)
+{
+	struct axp20x_dev *axp20x;
+	const struct of_device_id *of_id;
+	int ret;
+
+	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
+	if (!axp20x)
+		return -ENOMEM;
+
+	of_id = of_match_device(axp20x_of_match, &i2c->dev);
+	if (!of_id) {
+		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
+		return -ENODEV;
+	}
+	axp20x->variant = (long) of_id->data;
+
+	axp20x->i2c_client = i2c;
+	axp20x->dev = &i2c->dev;
+	dev_set_drvdata(axp20x->dev, axp20x);
+
+	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
+	if (IS_ERR(axp20x->regmap)) {
+		ret = PTR_ERR(axp20x->regmap);
+		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
+				  IRQF_ONESHOT | IRQF_SHARED, -1,
+				  &axp20x_regmap_irq_chip,
+				  &axp20x->regmap_irqc);
+	if (ret) {
+		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
+		return ret;
+	}
+
+	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
+			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+
+	if (ret) {
+		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
+		return ret;
+	}
+
+	if (!pm_power_off) {
+		axp20x_pm_power_off = axp20x;
+		pm_power_off = axp20x_power_off;
+	}
+
+	dev_info(&i2c->dev, "AXP20X driver loaded\n");
+
+	return 0;
+}
+
+static int axp20x_i2c_remove(struct i2c_client *i2c)
+{
+	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
+
+	if (axp20x == axp20x_pm_power_off) {
+		axp20x_pm_power_off = NULL;
+		pm_power_off = NULL;
+	}
+
+	mfd_remove_devices(axp20x->dev);
+	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
+
+	return 0;
+}
+
+static struct i2c_driver axp20x_i2c_driver = {
+	.driver = {
+		.name	= "axp20x",
+		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(axp20x_of_match),
+	},
+	.probe		= axp20x_i2c_probe,
+	.remove		= axp20x_i2c_remove,
+	.id_table	= axp20x_i2c_id,
+};
+
+module_i2c_driver(axp20x_i2c_driver);
+
+MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
deleted file mode 100644
index d0e31a2..0000000
--- a/include/linux/mfd/axp20x.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Functions and registers to access AXP20X power management chip.
- *
- * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
- *
- * 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 __LINUX_MFD_AXP20X_H
-#define __LINUX_MFD_AXP20X_H
-
-enum {
-	AXP202_ID = 0,
-	AXP209_ID,
-};
-
-#define AXP20X_DATACACHE(m)		(0x04 + (m))
-
-/* Power supply */
-#define AXP20X_PWR_INPUT_STATUS		0x00
-#define AXP20X_PWR_OP_MODE		0x01
-#define AXP20X_USB_OTG_STATUS		0x02
-#define AXP20X_PWR_OUT_CTRL		0x12
-#define AXP20X_DCDC2_V_OUT		0x23
-#define AXP20X_DCDC2_LDO3_V_SCAL	0x25
-#define AXP20X_DCDC3_V_OUT		0x27
-#define AXP20X_LDO24_V_OUT		0x28
-#define AXP20X_LDO3_V_OUT		0x29
-#define AXP20X_VBUS_IPSOUT_MGMT		0x30
-#define AXP20X_V_OFF			0x31
-#define AXP20X_OFF_CTRL			0x32
-#define AXP20X_CHRG_CTRL1		0x33
-#define AXP20X_CHRG_CTRL2		0x34
-#define AXP20X_CHRG_BAK_CTRL		0x35
-#define AXP20X_PEK_KEY			0x36
-#define AXP20X_DCDC_FREQ		0x37
-#define AXP20X_V_LTF_CHRG		0x38
-#define AXP20X_V_HTF_CHRG		0x39
-#define AXP20X_APS_WARN_L1		0x3a
-#define AXP20X_APS_WARN_L2		0x3b
-#define AXP20X_V_LTF_DISCHRG		0x3c
-#define AXP20X_V_HTF_DISCHRG		0x3d
-
-/* Interrupt */
-#define AXP20X_IRQ1_EN			0x40
-#define AXP20X_IRQ2_EN			0x41
-#define AXP20X_IRQ3_EN			0x42
-#define AXP20X_IRQ4_EN			0x43
-#define AXP20X_IRQ5_EN			0x44
-#define AXP20X_IRQ1_STATE		0x48
-#define AXP20X_IRQ2_STATE		0x49
-#define AXP20X_IRQ3_STATE		0x4a
-#define AXP20X_IRQ4_STATE		0x4b
-#define AXP20X_IRQ5_STATE		0x4c
-
-/* ADC */
-#define AXP20X_ACIN_V_ADC_H		0x56
-#define AXP20X_ACIN_V_ADC_L		0x57
-#define AXP20X_ACIN_I_ADC_H		0x58
-#define AXP20X_ACIN_I_ADC_L		0x59
-#define AXP20X_VBUS_V_ADC_H		0x5a
-#define AXP20X_VBUS_V_ADC_L		0x5b
-#define AXP20X_VBUS_I_ADC_H		0x5c
-#define AXP20X_VBUS_I_ADC_L		0x5d
-#define AXP20X_TEMP_ADC_H		0x5e
-#define AXP20X_TEMP_ADC_L		0x5f
-#define AXP20X_TS_IN_H			0x62
-#define AXP20X_TS_IN_L			0x63
-#define AXP20X_GPIO0_V_ADC_H		0x64
-#define AXP20X_GPIO0_V_ADC_L		0x65
-#define AXP20X_GPIO1_V_ADC_H		0x66
-#define AXP20X_GPIO1_V_ADC_L		0x67
-#define AXP20X_PWR_BATT_H		0x70
-#define AXP20X_PWR_BATT_M		0x71
-#define AXP20X_PWR_BATT_L		0x72
-#define AXP20X_BATT_V_H			0x78
-#define AXP20X_BATT_V_L			0x79
-#define AXP20X_BATT_CHRG_I_H		0x7a
-#define AXP20X_BATT_CHRG_I_L		0x7b
-#define AXP20X_BATT_DISCHRG_I_H		0x7c
-#define AXP20X_BATT_DISCHRG_I_L		0x7d
-#define AXP20X_IPSOUT_V_HIGH_H		0x7e
-#define AXP20X_IPSOUT_V_HIGH_L		0x7f
-
-/* Power supply */
-#define AXP20X_DCDC_MODE		0x80
-#define AXP20X_ADC_EN1			0x82
-#define AXP20X_ADC_EN2			0x83
-#define AXP20X_ADC_RATE			0x84
-#define AXP20X_GPIO10_IN_RANGE		0x85
-#define AXP20X_GPIO1_ADC_IRQ_RIS	0x86
-#define AXP20X_GPIO1_ADC_IRQ_FAL	0x87
-#define AXP20X_TIMER_CTRL		0x8a
-#define AXP20X_VBUS_MON			0x8b
-#define AXP20X_OVER_TMP			0x8f
-
-/* GPIO */
-#define AXP20X_GPIO0_CTRL		0x90
-#define AXP20X_LDO5_V_OUT		0x91
-#define AXP20X_GPIO1_CTRL		0x92
-#define AXP20X_GPIO2_CTRL		0x93
-#define AXP20X_GPIO20_SS		0x94
-#define AXP20X_GPIO3_CTRL		0x95
-
-/* Battery */
-#define AXP20X_CHRG_CC_31_24		0xb0
-#define AXP20X_CHRG_CC_23_16		0xb1
-#define AXP20X_CHRG_CC_15_8		0xb2
-#define AXP20X_CHRG_CC_7_0		0xb3
-#define AXP20X_DISCHRG_CC_31_24		0xb4
-#define AXP20X_DISCHRG_CC_23_16		0xb5
-#define AXP20X_DISCHRG_CC_15_8		0xb6
-#define AXP20X_DISCHRG_CC_7_0		0xb7
-#define AXP20X_CC_CTRL			0xb8
-#define AXP20X_FG_RES			0xb9
-
-/* Regulators IDs */
-enum {
-	AXP20X_LDO1 = 0,
-	AXP20X_LDO2,
-	AXP20X_LDO3,
-	AXP20X_LDO4,
-	AXP20X_LDO5,
-	AXP20X_DCDC2,
-	AXP20X_DCDC3,
-	AXP20X_REG_ID_MAX,
-};
-
-/* IRQs */
-enum {
-	AXP20X_IRQ_ACIN_OVER_V = 1,
-	AXP20X_IRQ_ACIN_PLUGIN,
-	AXP20X_IRQ_ACIN_REMOVAL,
-	AXP20X_IRQ_VBUS_OVER_V,
-	AXP20X_IRQ_VBUS_PLUGIN,
-	AXP20X_IRQ_VBUS_REMOVAL,
-	AXP20X_IRQ_VBUS_V_LOW,
-	AXP20X_IRQ_BATT_PLUGIN,
-	AXP20X_IRQ_BATT_REMOVAL,
-	AXP20X_IRQ_BATT_ENT_ACT_MODE,
-	AXP20X_IRQ_BATT_EXIT_ACT_MODE,
-	AXP20X_IRQ_CHARG,
-	AXP20X_IRQ_CHARG_DONE,
-	AXP20X_IRQ_BATT_TEMP_HIGH,
-	AXP20X_IRQ_BATT_TEMP_LOW,
-	AXP20X_IRQ_DIE_TEMP_HIGH,
-	AXP20X_IRQ_CHARG_I_LOW,
-	AXP20X_IRQ_DCDC1_V_LONG,
-	AXP20X_IRQ_DCDC2_V_LONG,
-	AXP20X_IRQ_DCDC3_V_LONG,
-	AXP20X_IRQ_PEK_SHORT = 22,
-	AXP20X_IRQ_PEK_LONG,
-	AXP20X_IRQ_N_OE_PWR_ON,
-	AXP20X_IRQ_N_OE_PWR_OFF,
-	AXP20X_IRQ_VBUS_VALID,
-	AXP20X_IRQ_VBUS_NOT_VALID,
-	AXP20X_IRQ_VBUS_SESS_VALID,
-	AXP20X_IRQ_VBUS_SESS_END,
-	AXP20X_IRQ_LOW_PWR_LVL1,
-	AXP20X_IRQ_LOW_PWR_LVL2,
-	AXP20X_IRQ_TIMER,
-	AXP20X_IRQ_PEK_RIS_EDGE,
-	AXP20X_IRQ_PEK_FAL_EDGE,
-	AXP20X_IRQ_GPIO3_INPUT,
-	AXP20X_IRQ_GPIO2_INPUT,
-	AXP20X_IRQ_GPIO1_INPUT,
-	AXP20X_IRQ_GPIO0_INPUT,
-};
-
-struct axp20x_dev {
-	struct device			*dev;
-	struct i2c_client		*i2c_client;
-	struct regmap			*regmap;
-	struct regmap_irq_chip_data	*regmap_irqc;
-	long				variant;
-};
-
-#endif /* __LINUX_MFD_AXP20X_H */
diff --git a/include/linux/mfd/axp2xx.h b/include/linux/mfd/axp2xx.h
new file mode 100644
index 0000000..d0e31a2
--- /dev/null
+++ b/include/linux/mfd/axp2xx.h
@@ -0,0 +1,180 @@
+/*
+ * Functions and registers to access AXP20X power management chip.
+ *
+ * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
+ *
+ * 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 __LINUX_MFD_AXP20X_H
+#define __LINUX_MFD_AXP20X_H
+
+enum {
+	AXP202_ID = 0,
+	AXP209_ID,
+};
+
+#define AXP20X_DATACACHE(m)		(0x04 + (m))
+
+/* Power supply */
+#define AXP20X_PWR_INPUT_STATUS		0x00
+#define AXP20X_PWR_OP_MODE		0x01
+#define AXP20X_USB_OTG_STATUS		0x02
+#define AXP20X_PWR_OUT_CTRL		0x12
+#define AXP20X_DCDC2_V_OUT		0x23
+#define AXP20X_DCDC2_LDO3_V_SCAL	0x25
+#define AXP20X_DCDC3_V_OUT		0x27
+#define AXP20X_LDO24_V_OUT		0x28
+#define AXP20X_LDO3_V_OUT		0x29
+#define AXP20X_VBUS_IPSOUT_MGMT		0x30
+#define AXP20X_V_OFF			0x31
+#define AXP20X_OFF_CTRL			0x32
+#define AXP20X_CHRG_CTRL1		0x33
+#define AXP20X_CHRG_CTRL2		0x34
+#define AXP20X_CHRG_BAK_CTRL		0x35
+#define AXP20X_PEK_KEY			0x36
+#define AXP20X_DCDC_FREQ		0x37
+#define AXP20X_V_LTF_CHRG		0x38
+#define AXP20X_V_HTF_CHRG		0x39
+#define AXP20X_APS_WARN_L1		0x3a
+#define AXP20X_APS_WARN_L2		0x3b
+#define AXP20X_V_LTF_DISCHRG		0x3c
+#define AXP20X_V_HTF_DISCHRG		0x3d
+
+/* Interrupt */
+#define AXP20X_IRQ1_EN			0x40
+#define AXP20X_IRQ2_EN			0x41
+#define AXP20X_IRQ3_EN			0x42
+#define AXP20X_IRQ4_EN			0x43
+#define AXP20X_IRQ5_EN			0x44
+#define AXP20X_IRQ1_STATE		0x48
+#define AXP20X_IRQ2_STATE		0x49
+#define AXP20X_IRQ3_STATE		0x4a
+#define AXP20X_IRQ4_STATE		0x4b
+#define AXP20X_IRQ5_STATE		0x4c
+
+/* ADC */
+#define AXP20X_ACIN_V_ADC_H		0x56
+#define AXP20X_ACIN_V_ADC_L		0x57
+#define AXP20X_ACIN_I_ADC_H		0x58
+#define AXP20X_ACIN_I_ADC_L		0x59
+#define AXP20X_VBUS_V_ADC_H		0x5a
+#define AXP20X_VBUS_V_ADC_L		0x5b
+#define AXP20X_VBUS_I_ADC_H		0x5c
+#define AXP20X_VBUS_I_ADC_L		0x5d
+#define AXP20X_TEMP_ADC_H		0x5e
+#define AXP20X_TEMP_ADC_L		0x5f
+#define AXP20X_TS_IN_H			0x62
+#define AXP20X_TS_IN_L			0x63
+#define AXP20X_GPIO0_V_ADC_H		0x64
+#define AXP20X_GPIO0_V_ADC_L		0x65
+#define AXP20X_GPIO1_V_ADC_H		0x66
+#define AXP20X_GPIO1_V_ADC_L		0x67
+#define AXP20X_PWR_BATT_H		0x70
+#define AXP20X_PWR_BATT_M		0x71
+#define AXP20X_PWR_BATT_L		0x72
+#define AXP20X_BATT_V_H			0x78
+#define AXP20X_BATT_V_L			0x79
+#define AXP20X_BATT_CHRG_I_H		0x7a
+#define AXP20X_BATT_CHRG_I_L		0x7b
+#define AXP20X_BATT_DISCHRG_I_H		0x7c
+#define AXP20X_BATT_DISCHRG_I_L		0x7d
+#define AXP20X_IPSOUT_V_HIGH_H		0x7e
+#define AXP20X_IPSOUT_V_HIGH_L		0x7f
+
+/* Power supply */
+#define AXP20X_DCDC_MODE		0x80
+#define AXP20X_ADC_EN1			0x82
+#define AXP20X_ADC_EN2			0x83
+#define AXP20X_ADC_RATE			0x84
+#define AXP20X_GPIO10_IN_RANGE		0x85
+#define AXP20X_GPIO1_ADC_IRQ_RIS	0x86
+#define AXP20X_GPIO1_ADC_IRQ_FAL	0x87
+#define AXP20X_TIMER_CTRL		0x8a
+#define AXP20X_VBUS_MON			0x8b
+#define AXP20X_OVER_TMP			0x8f
+
+/* GPIO */
+#define AXP20X_GPIO0_CTRL		0x90
+#define AXP20X_LDO5_V_OUT		0x91
+#define AXP20X_GPIO1_CTRL		0x92
+#define AXP20X_GPIO2_CTRL		0x93
+#define AXP20X_GPIO20_SS		0x94
+#define AXP20X_GPIO3_CTRL		0x95
+
+/* Battery */
+#define AXP20X_CHRG_CC_31_24		0xb0
+#define AXP20X_CHRG_CC_23_16		0xb1
+#define AXP20X_CHRG_CC_15_8		0xb2
+#define AXP20X_CHRG_CC_7_0		0xb3
+#define AXP20X_DISCHRG_CC_31_24		0xb4
+#define AXP20X_DISCHRG_CC_23_16		0xb5
+#define AXP20X_DISCHRG_CC_15_8		0xb6
+#define AXP20X_DISCHRG_CC_7_0		0xb7
+#define AXP20X_CC_CTRL			0xb8
+#define AXP20X_FG_RES			0xb9
+
+/* Regulators IDs */
+enum {
+	AXP20X_LDO1 = 0,
+	AXP20X_LDO2,
+	AXP20X_LDO3,
+	AXP20X_LDO4,
+	AXP20X_LDO5,
+	AXP20X_DCDC2,
+	AXP20X_DCDC3,
+	AXP20X_REG_ID_MAX,
+};
+
+/* IRQs */
+enum {
+	AXP20X_IRQ_ACIN_OVER_V = 1,
+	AXP20X_IRQ_ACIN_PLUGIN,
+	AXP20X_IRQ_ACIN_REMOVAL,
+	AXP20X_IRQ_VBUS_OVER_V,
+	AXP20X_IRQ_VBUS_PLUGIN,
+	AXP20X_IRQ_VBUS_REMOVAL,
+	AXP20X_IRQ_VBUS_V_LOW,
+	AXP20X_IRQ_BATT_PLUGIN,
+	AXP20X_IRQ_BATT_REMOVAL,
+	AXP20X_IRQ_BATT_ENT_ACT_MODE,
+	AXP20X_IRQ_BATT_EXIT_ACT_MODE,
+	AXP20X_IRQ_CHARG,
+	AXP20X_IRQ_CHARG_DONE,
+	AXP20X_IRQ_BATT_TEMP_HIGH,
+	AXP20X_IRQ_BATT_TEMP_LOW,
+	AXP20X_IRQ_DIE_TEMP_HIGH,
+	AXP20X_IRQ_CHARG_I_LOW,
+	AXP20X_IRQ_DCDC1_V_LONG,
+	AXP20X_IRQ_DCDC2_V_LONG,
+	AXP20X_IRQ_DCDC3_V_LONG,
+	AXP20X_IRQ_PEK_SHORT = 22,
+	AXP20X_IRQ_PEK_LONG,
+	AXP20X_IRQ_N_OE_PWR_ON,
+	AXP20X_IRQ_N_OE_PWR_OFF,
+	AXP20X_IRQ_VBUS_VALID,
+	AXP20X_IRQ_VBUS_NOT_VALID,
+	AXP20X_IRQ_VBUS_SESS_VALID,
+	AXP20X_IRQ_VBUS_SESS_END,
+	AXP20X_IRQ_LOW_PWR_LVL1,
+	AXP20X_IRQ_LOW_PWR_LVL2,
+	AXP20X_IRQ_TIMER,
+	AXP20X_IRQ_PEK_RIS_EDGE,
+	AXP20X_IRQ_PEK_FAL_EDGE,
+	AXP20X_IRQ_GPIO3_INPUT,
+	AXP20X_IRQ_GPIO2_INPUT,
+	AXP20X_IRQ_GPIO1_INPUT,
+	AXP20X_IRQ_GPIO0_INPUT,
+};
+
+struct axp20x_dev {
+	struct device			*dev;
+	struct i2c_client		*i2c_client;
+	struct regmap			*regmap;
+	struct regmap_irq_chip_data	*regmap_irqc;
+	long				variant;
+};
+
+#endif /* __LINUX_MFD_AXP20X_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic
  2014-09-08 22:24 [PATCH 0/4] Initial support for XPowers AXP288 PMIC Jacob Pan
  2014-09-08 22:24 ` [PATCH 1/4] mfd/axp20x: rename files to support more devices Jacob Pan
@ 2014-09-08 22:24 ` Jacob Pan
  2014-09-09  7:37   ` Maxime Ripard
  2014-09-08 22:24 ` [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header Jacob Pan
  2014-09-08 22:24 ` [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc Jacob Pan
  3 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-08 22:24 UTC (permalink / raw)
  To: IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Aaron Lu, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson, Jacob Pan

XPower AXP288 is a customized PMIC for Intel Baytrail-CR platforms. Similar
to AXP202/209, AXP288 comes with USB charger, more LDO and BUCK channels, and
AD converter. It also provides extended status and interrupt reporting
capabilities than the devices supported in axp20x.c.

In addition to feature extension, this patch also adds ACPI binding for
enumeration and hooks for ACPI custom operational region handlers.

Files and common data structures have been renamed from axp20x to axp2xx
in order to suit the extended scope of devices.

This consolidated driver should support more Xpower PMICs in both device
tree and ACPI based platforms.

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 drivers/mfd/axp2xx.c       | 424 +++++++++++++++++++++++++++++++++++----------
 include/linux/mfd/axp2xx.h |  57 +++++-
 2 files changed, 389 insertions(+), 92 deletions(-)

diff --git a/drivers/mfd/axp2xx.c b/drivers/mfd/axp2xx.c
index c534443..cf7ed16 100644
--- a/drivers/mfd/axp2xx.c
+++ b/drivers/mfd/axp2xx.c
@@ -1,10 +1,14 @@
 /*
- * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ * axp2xx.c - MFD core driver for the X-Powers AXP202, AXP209, and AXP288
  *
  * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
  * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
  * as well as 4 configurable GPIOs.
  *
+ * AXP288 is a customized PMIC for Intel Baytrail CR platform. Similar to AXP20x
+ * it comes with USB charger, more LDO, BUCK channels, and status reporting
+ * capabilities.
+ *
  * Author: Carlo Caione <carlo@caione.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,9 +29,14 @@
 #include <linux/mfd/core.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/acpi.h>
 
 #define AXP20X_OFF	0x80
 
+static struct mfd_cell *axp2xx_cells;
+static int axp2xx_nr_cells;
+static struct regmap_config *regmap_cfg;
+
 static const struct regmap_range axp20x_writeable_ranges[] = {
 	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
 	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
@@ -47,6 +56,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
 	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
 };
 
+static const struct regmap_range axp288_writeable_ranges[] = {
+	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
+	regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
+};
+
+static const struct regmap_range axp288_volatile_ranges[] = {
+	regmap_reg_range(AXP20X_IRQ1_EN,  AXP20X_IPSOUT_V_HIGH_L),
+};
+
+static const struct regmap_access_table axp288_writeable_table = {
+	.yes_ranges	= axp288_writeable_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(axp288_writeable_ranges),
+};
+
+static const struct regmap_access_table axp288_volatile_table = {
+	.yes_ranges	= axp288_volatile_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(axp288_volatile_ranges),
+};
+
 static struct resource axp20x_pek_resources[] = {
 	{
 		.name	= "PEK_DBR",
@@ -61,7 +89,40 @@ static struct resource axp20x_pek_resources[] = {
 	},
 };
 
-static const struct regmap_config axp20x_regmap_config = {
+static struct resource axp288_battery_resources[] = {
+	{
+		.start = AXP288_IRQ_QWBTU,
+		.end   = AXP288_IRQ_QWBTU,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_WBTU,
+		.end   = AXP288_IRQ_WBTU,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_QWBTO,
+		.end   = AXP288_IRQ_QWBTO,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_WBTO,
+		.end   = AXP288_IRQ_WBTO,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_WL2,
+		.end   = AXP288_IRQ_WL2,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_WL1,
+		.end   = AXP288_IRQ_WL1,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct regmap_config axp20x_regmap_config = {
 	.reg_bits	= 8,
 	.val_bits	= 8,
 	.wr_table	= &axp20x_writeable_table,
@@ -70,47 +131,96 @@ static const struct regmap_config axp20x_regmap_config = {
 	.cache_type	= REGCACHE_RBTREE,
 };
 
-#define AXP20X_IRQ(_irq, _off, _mask) \
-	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+static struct regmap_config axp288_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.wr_table	= &axp288_writeable_table,
+	.volatile_table	= &axp288_volatile_table,
+	.max_register	= AXP288_FG_TUNE5,
+	.cache_type	= REGCACHE_RBTREE,
+};
+
+#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask)			\
+	[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
 
 static const struct regmap_irq axp20x_regmap_irqs[] = {
-	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
-	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
-	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
-	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
-	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
-	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
-	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
-	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
-	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
-	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
-	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
-	AXP20X_IRQ(CHARG,		1, 3),
-	AXP20X_IRQ(CHARG_DONE,		1, 2),
-	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
-	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
-	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
-	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
-	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
-	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
-	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
-	AXP20X_IRQ(PEK_SHORT,		2, 1),
-	AXP20X_IRQ(PEK_LONG,		2, 0),
-	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
-	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
-	AXP20X_IRQ(VBUS_VALID,		3, 5),
-	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
-	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
-	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
-	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
-	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
-	AXP20X_IRQ(TIMER,		4, 7),
-	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
-	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
-	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
-	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
-	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
-	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
+	INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V,		0, 7),
+	INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN,		0, 6),
+	INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL,	        0, 5),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,		0, 4),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,		0, 3),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,	        0, 2),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW,		0, 1),
+	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,		1, 7),
+	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,	        1, 6),
+	INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE,	1, 5),
+	INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE,	1, 4),
+	INIT_REGMAP_IRQ(AXP20X, CHARG,		        1, 3),
+	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,		1, 2),
+	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH,	        1, 1),
+	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW,	        1, 0),
+	INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH,	        2, 7),
+	INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW,		2, 6),
+	INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG,	        2, 5),
+	INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG,	        2, 4),
+	INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG,	        2, 3),
+	INIT_REGMAP_IRQ(AXP20X, PEK_SHORT,		2, 1),
+	INIT_REGMAP_IRQ(AXP20X, PEK_LONG,		2, 0),
+	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON,		3, 7),
+	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF,	        3, 6),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_VALID,		3, 5),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID,	        3, 4),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID,	3, 3),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END,	        3, 2),
+	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1,	        3, 1),
+	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2,	        3, 0),
+	INIT_REGMAP_IRQ(AXP20X, TIMER,		        4, 7),
+	INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE,	        4, 6),
+	INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE,	        4, 5),
+	INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT,		4, 3),
+	INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT,		4, 2),
+	INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT,		4, 1),
+	INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT,		4, 0),
+};
+
+/* some IRQs are compatible with axp20x models */
+static const struct regmap_irq axp288_regmap_irqs[] = {
+	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,           0, 2),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,            0, 3),
+	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,            0, 4),
+
+	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,             1, 2),
+	INIT_REGMAP_IRQ(AXP20X, CHARG,                  1, 3),
+	INIT_REGMAP_IRQ(AXP288, SAFE_QUIT,              1, 4),
+	INIT_REGMAP_IRQ(AXP288, SAFE_ENTER,             1, 5),
+	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,           1, 6),
+	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,            1, 7),
+
+	INIT_REGMAP_IRQ(AXP288, QWBTU,                  2, 0),
+	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 1),
+	INIT_REGMAP_IRQ(AXP288, QWBTO,                  2, 2),
+	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 3),
+	INIT_REGMAP_IRQ(AXP288, QCBTU,                  2, 4),
+	INIT_REGMAP_IRQ(AXP288, CBTU,                   2, 5),
+	INIT_REGMAP_IRQ(AXP288, QCBTO,                  2, 6),
+	INIT_REGMAP_IRQ(AXP288, CBTO,                   2, 7),
+
+	INIT_REGMAP_IRQ(AXP288, WL2,                    3, 0),
+	INIT_REGMAP_IRQ(AXP288, WL1,                    3, 1),
+	INIT_REGMAP_IRQ(AXP288, GPADC,                  3, 2),
+	INIT_REGMAP_IRQ(AXP288, OT,                     3, 7),
+
+	INIT_REGMAP_IRQ(AXP288, GPIO0,                  4, 0),
+	INIT_REGMAP_IRQ(AXP288, GPIO1,                  4, 1),
+	INIT_REGMAP_IRQ(AXP288, POKO,                   4, 2),
+	INIT_REGMAP_IRQ(AXP288, POKL,                   4, 3),
+	INIT_REGMAP_IRQ(AXP288, POKS,                   4, 4),
+	INIT_REGMAP_IRQ(AXP288, POKN,                   4, 5),
+	INIT_REGMAP_IRQ(AXP288, POKP,                   4, 6),
+	INIT_REGMAP_IRQ(AXP20X, TIMER,                  4, 7),
+
+	INIT_REGMAP_IRQ(AXP288, MV_CHNG,                5, 0),
+	INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG,            5, 1),
 };
 
 static const struct of_device_id axp20x_of_match[] = {
@@ -123,19 +233,26 @@ MODULE_DEVICE_TABLE(of, axp20x_of_match);
 /*
  * This is useless for OF-enabled devices, but it is needed by I2C subsystem
  */
-static const struct i2c_device_id axp20x_i2c_id[] = {
+static const struct i2c_device_id axp2xx_i2c_id[] = {
 	{ },
 };
-MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
+MODULE_DEVICE_TABLE(i2c, axp2xx_i2c_id);
 
-static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
-	.name			= "axp20x_irq_chip",
+static struct acpi_device_id axp2xx_acpi_match[] = {
+	{
+		.id = "INT33F4",
+		.driver_data = (kernel_ulong_t)AXP288_ID,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, axp2xx_acpi_match);
+
+/* common irq chip attributes only */
+static struct regmap_irq_chip axp2xx_regmap_irq_chip = {
+	.name			= "axp2xx_irq_chip",
 	.status_base		= AXP20X_IRQ1_STATE,
 	.ack_base		= AXP20X_IRQ1_STATE,
 	.mask_base		= AXP20X_IRQ1_EN,
-	.num_regs		= 5,
-	.irqs			= axp20x_regmap_irqs,
-	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
 	.mask_invert		= true,
 	.init_ack_masked	= true,
 };
@@ -161,98 +278,223 @@ static struct mfd_cell axp20x_cells[] = {
 	},
 };
 
-static struct axp20x_dev *axp20x_pm_power_off;
-static void axp20x_power_off(void)
+static struct resource axp288_adc_resources[] = {
+	{
+		.name	= "GPADC",
+		.start = AXP288_IRQ_GPADC,
+		.end   = AXP288_IRQ_GPADC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource axp288_charger_resources[] = {
+	{
+		.start = AXP288_IRQ_OV,
+		.end   = AXP288_IRQ_OV,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_DONE,
+		.end   = AXP288_IRQ_DONE,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_CHARGING,
+		.end   = AXP288_IRQ_CHARGING,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_SAFE_QUIT,
+		.end   = AXP288_IRQ_SAFE_QUIT,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_SAFE_ENTER,
+		.end   = AXP288_IRQ_SAFE_ENTER,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_QCBTU,
+		.end   = AXP288_IRQ_QCBTU,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_CBTU,
+		.end   = AXP288_IRQ_CBTU,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_QCBTO,
+		.end   = AXP288_IRQ_QCBTO,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = AXP288_IRQ_CBTO,
+		.end   = AXP288_IRQ_CBTO,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell axp288_cells[] = {
+	{
+		.name = "axp288_adc",
+		.num_resources = ARRAY_SIZE(axp288_adc_resources),
+		.resources = axp288_adc_resources,
+	},
+	{
+		.name = "axp288_charger",
+		.num_resources = ARRAY_SIZE(axp288_charger_resources),
+		.resources = axp288_charger_resources,
+	},
+	{
+		.name = "axp288_battery",
+		.num_resources = ARRAY_SIZE(axp288_battery_resources),
+		.resources = axp288_battery_resources,
+	},
+	{
+		.name = "axp288_acpi_opregion",
+	},
+};
+
+static struct axp2xx_dev *axp2xx_pm_power_off;
+static void axp2xx_power_off(void)
 {
-	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
+	if (axp2xx_pm_power_off->variant == AXP288_ID)
+		return;
+	regmap_write(axp2xx_pm_power_off->regmap, AXP20X_OFF_CTRL,
 		     AXP20X_OFF);
 }
 
-static int axp20x_i2c_probe(struct i2c_client *i2c,
-			 const struct i2c_device_id *id)
+static int axp2xx_match_device(struct axp2xx_dev *axp2xx, struct device *dev)
 {
-	struct axp20x_dev *axp20x;
+	const struct acpi_device_id *acpi_id;
 	const struct of_device_id *of_id;
-	int ret;
 
-	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
-	if (!axp20x)
-		return -ENOMEM;
+	of_id = of_match_device(axp2xx_of_match, dev);
+	if (of_id) {
+		axp2xx->variant = (long) of_id->data;
+		goto found_match;
+	}
 
-	of_id = of_match_device(axp20x_of_match, &i2c->dev);
-	if (!of_id) {
-		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
+	acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!acpi_id || !acpi_id->driver_data) {
+		dev_err(dev, "Unable to setup AXP2XX ACPI data\n");
 		return -ENODEV;
 	}
-	axp20x->variant = (long) of_id->data;
+	axp2xx->variant = (long) acpi_id->driver_data;
+
+found_match:
+	switch (axp2xx->variant) {
+	case AXP202_ID:
+	case AXP209_ID:
+		dev_dbg(dev, "AXP2xx variant AXP202/209 found\n");
+		axp2xx_nr_cells = ARRAY_SIZE(axp20x_cells);
+		axp2xx_cells = axp20x_cells;
+		regmap_cfg = &axp20x_regmap_config;
+		axp2xx_regmap_irq_chip.num_regs	= 5;
+		axp2xx_regmap_irq_chip.irqs = axp20x_regmap_irqs;
+		axp2xx_regmap_irq_chip.num_irqs	=
+			ARRAY_SIZE(axp20x_regmap_irqs);
+		break;
+	case AXP288_ID:
+		dev_dbg(dev, "AXP2xx variant AXP288 found\n");
+		axp2xx_cells = axp288_cells;
+		axp2xx_nr_cells = ARRAY_SIZE(axp288_cells);
+		axp2xx_regmap_irq_chip.irqs = axp288_regmap_irqs;
+		axp2xx_regmap_irq_chip.num_irqs	=
+			ARRAY_SIZE(axp288_regmap_irqs);
+		axp2xx_regmap_irq_chip.num_regs	= 6;
+		regmap_cfg = &axp288_regmap_config;
+		break;
+	default:
+		dev_err(dev, "unsupported AXP2XX ID %lu\n", axp2xx->variant);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int axp2xx_i2c_probe(struct i2c_client *i2c,
+			const struct i2c_device_id *id)
+{
+	struct axp2xx_dev *axp2xx;
+	int ret;
 
-	axp20x->i2c_client = i2c;
-	axp20x->dev = &i2c->dev;
-	dev_set_drvdata(axp20x->dev, axp20x);
+	axp2xx = devm_kzalloc(&i2c->dev, sizeof(*axp2xx), GFP_KERNEL);
+	if (!axp2xx)
+		return -ENOMEM;
+
+	ret = axp2xx_match_device(axp2xx, &i2c->dev);
+	if (ret)
+		return ret;
+	axp2xx->i2c_client = i2c;
+	axp2xx->dev = &i2c->dev;
+	dev_set_drvdata(axp2xx->dev, axp2xx);
 
-	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
-	if (IS_ERR(axp20x->regmap)) {
-		ret = PTR_ERR(axp20x->regmap);
+	axp2xx->regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
+	if (IS_ERR(axp2xx->regmap)) {
+		ret = PTR_ERR(axp2xx->regmap);
 		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
 		return ret;
 	}
 
-	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
+	ret = regmap_add_irq_chip(axp2xx->regmap, i2c->irq,
 				  IRQF_ONESHOT | IRQF_SHARED, -1,
-				  &axp20x_regmap_irq_chip,
-				  &axp20x->regmap_irqc);
+				  &axp2xx_regmap_irq_chip,
+				  &axp2xx->regmap_irqc);
 	if (ret) {
 		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
 		return ret;
 	}
 
-	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
-			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+	ret = mfd_add_devices(axp2xx->dev, -1, axp2xx_cells,
+			axp2xx_nr_cells, NULL, 0, NULL);
 
 	if (ret) {
 		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
-		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
+		regmap_del_irq_chip(i2c->irq, axp2xx->regmap_irqc);
 		return ret;
 	}
 
 	if (!pm_power_off) {
-		axp20x_pm_power_off = axp20x;
-		pm_power_off = axp20x_power_off;
+		axp2xx_pm_power_off = axp2xx;
+		pm_power_off = axp2xx_power_off;
 	}
 
-	dev_info(&i2c->dev, "AXP20X driver loaded\n");
+	dev_info(&i2c->dev, "AXP2XX driver loaded\n");
 
 	return 0;
 }
 
-static int axp20x_i2c_remove(struct i2c_client *i2c)
+static int axp2xx_i2c_remove(struct i2c_client *i2c)
 {
-	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
+	struct axp2xx_dev *axp2xx = i2c_get_clientdata(i2c);
 
-	if (axp20x == axp20x_pm_power_off) {
-		axp20x_pm_power_off = NULL;
+	if (axp2xx == axp2xx_pm_power_off) {
+		axp2xx_pm_power_off = NULL;
 		pm_power_off = NULL;
 	}
 
-	mfd_remove_devices(axp20x->dev);
-	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
+	mfd_remove_devices(axp2xx->dev);
+	regmap_del_irq_chip(axp2xx->i2c_client->irq, axp2xx->regmap_irqc);
 
 	return 0;
 }
 
-static struct i2c_driver axp20x_i2c_driver = {
+static struct i2c_driver axp2xx_i2c_driver = {
 	.driver = {
-		.name	= "axp20x",
+		.name	= "axp2xx",
 		.owner	= THIS_MODULE,
-		.of_match_table	= of_match_ptr(axp20x_of_match),
+		.of_match_table	= of_match_ptr(axp2xx_of_match),
+		.acpi_match_table = ACPI_PTR(axp2xx_acpi_match),
 	},
-	.probe		= axp20x_i2c_probe,
-	.remove		= axp20x_i2c_remove,
-	.id_table	= axp20x_i2c_id,
+	.probe		= axp2xx_i2c_probe,
+	.remove		= axp2xx_i2c_remove,
+	.id_table	= axp2xx_i2c_id,
 };
 
-module_i2c_driver(axp20x_i2c_driver);
+module_i2c_driver(axp2xx_i2c_driver);
 
-MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
+MODULE_DESCRIPTION("PMIC MFD core driver for AXP2XX");
 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/axp2xx.h b/include/linux/mfd/axp2xx.h
index d0e31a2..672f048 100644
--- a/include/linux/mfd/axp2xx.h
+++ b/include/linux/mfd/axp2xx.h
@@ -14,6 +14,8 @@
 enum {
 	AXP202_ID = 0,
 	AXP209_ID,
+	AXP288_ID,
+	NR_AXP288_VARIANTS,
 };
 
 #define AXP20X_DATACACHE(m)		(0x04 + (m))
@@ -49,11 +51,13 @@ enum {
 #define AXP20X_IRQ3_EN			0x42
 #define AXP20X_IRQ4_EN			0x43
 #define AXP20X_IRQ5_EN			0x44
+#define AXP20X_IRQ6_EN			0x45
 #define AXP20X_IRQ1_STATE		0x48
 #define AXP20X_IRQ2_STATE		0x49
 #define AXP20X_IRQ3_STATE		0x4a
 #define AXP20X_IRQ4_STATE		0x4b
 #define AXP20X_IRQ5_STATE		0x4c
+#define AXP20X_IRQ6_STATE		0x4d
 
 /* ADC */
 #define AXP20X_ACIN_V_ADC_H		0x56
@@ -116,6 +120,15 @@ enum {
 #define AXP20X_CC_CTRL			0xb8
 #define AXP20X_FG_RES			0xb9
 
+/* AXP288 specific registers */
+#define AXP288_PMIC_ADC_H               0x56
+#define AXP288_PMIC_ADC_L               0x57
+#define AXP288_ADC_TS_PIN_CTRL          0x84
+
+#define AXP288_PMIC_ADC_EN              0x84
+#define AXP288_FG_TUNE5			0xed
+
+
 /* Regulators IDs */
 enum {
 	AXP20X_LDO1 = 0,
@@ -169,7 +182,49 @@ enum {
 	AXP20X_IRQ_GPIO0_INPUT,
 };
 
-struct axp20x_dev {
+enum axp288_irqs {
+	AXP288_IRQ_VBUS_FALL     = 2,
+	AXP288_IRQ_VBUS_RISE,
+	AXP288_IRQ_OV,
+	AXP288_IRQ_FALLING_ALT,
+	AXP288_IRQ_RISING_ALT,
+	AXP288_IRQ_OV_ALT,
+	AXP288_IRQ_DONE          = 10,
+	AXP288_IRQ_CHARGING,
+	AXP288_IRQ_SAFE_QUIT,
+	AXP288_IRQ_SAFE_ENTER,
+	AXP288_IRQ_ABSENT,
+	AXP288_IRQ_APPEND,
+	AXP288_IRQ_QWBTU,
+	AXP288_IRQ_WBTU,
+	AXP288_IRQ_QWBTO,
+	AXP288_IRQ_WBTO,
+	AXP288_IRQ_QCBTU,
+	AXP288_IRQ_CBTU,
+	AXP288_IRQ_QCBTO,
+	AXP288_IRQ_CBTO,
+	AXP288_IRQ_WL2,
+	AXP288_IRQ_WL1,
+	AXP288_IRQ_GPADC,
+	AXP288_IRQ_OT            = 31,
+	AXP288_IRQ_GPIO0,
+	AXP288_IRQ_GPIO1,
+	AXP288_IRQ_POKO,
+	AXP288_IRQ_POKL,
+	AXP288_IRQ_POKS,
+	AXP288_IRQ_POKN,
+	AXP288_IRQ_POKP,
+	AXP288_IRQ_TIMER,
+	AXP288_IRQ_MV_CHNG,
+	AXP288_IRQ_BC_USB_CHNG,
+};
+
+#define AXP288_TS_ADC_H		0x58
+#define AXP288_TS_ADC_L		0x59
+#define AXP288_GP_ADC_H		0x5a
+#define AXP288_GP_ADC_L		0x5b
+
+struct axp2xx_dev {
 	struct device			*dev;
 	struct i2c_client		*i2c_client;
 	struct regmap			*regmap;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header
  2014-09-08 22:24 [PATCH 0/4] Initial support for XPowers AXP288 PMIC Jacob Pan
  2014-09-08 22:24 ` [PATCH 1/4] mfd/axp20x: rename files to support more devices Jacob Pan
  2014-09-08 22:24 ` [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic Jacob Pan
@ 2014-09-08 22:24 ` Jacob Pan
  2014-09-09 11:25   ` Mark Brown
  2014-09-08 22:24 ` [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc Jacob Pan
  3 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-08 22:24 UTC (permalink / raw)
  To: IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Aaron Lu, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson, Jacob Pan

AXP20x driver has been extended to support axp288 variant. Header file
and common data structures has also been renamed to suit the new
scope of devices supported.

This patch makes use of the renamed header and structure.

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 drivers/regulator/axp20x-regulator.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 004aadb..c9b6803 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -20,7 +20,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/mfd/axp20x.h>
+#include <linux/mfd/axp2xx.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 
@@ -161,7 +161,7 @@ static struct of_regulator_match axp20x_matches[] = {
 
 static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
 {
-	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+	struct axp2xx_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 
 	if (dcdcfreq < 750) {
 		dcdcfreq = 750;
@@ -232,7 +232,7 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
 static int axp20x_regulator_probe(struct platform_device *pdev)
 {
 	struct regulator_dev *rdev;
-	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+	struct axp2xx_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 	struct regulator_config config = { };
 	struct regulator_init_data *init_data;
 	int ret, i;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc
  2014-09-08 22:24 [PATCH 0/4] Initial support for XPowers AXP288 PMIC Jacob Pan
                   ` (2 preceding siblings ...)
  2014-09-08 22:24 ` [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header Jacob Pan
@ 2014-09-08 22:24 ` Jacob Pan
  2014-09-10  4:19   ` Pallala, Ramakrishna
  3 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-08 22:24 UTC (permalink / raw)
  To: IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Aaron Lu, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson, Jacob Pan

Platform driver for XPowers AXP288 ADC, which is a customized PMIC for Intel
Baytrail-CR platforms. GPADC device enumerates as one of the PMIC MFD cell
devices. It uses IIO infrastructure to communicate with userspace and
consumer drivers.

Usages of ADC channels include battery charging and thermal sensors.

Based on initial work by:
Ramakrishna Pallala <ramakrishna.pallala@intel.com>

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 drivers/iio/adc/Kconfig        |   8 ++
 drivers/iio/adc/Makefile       |   1 +
 drivers/iio/adc/axp288_gpadc.c | 250 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 259 insertions(+)
 create mode 100644 drivers/iio/adc/axp288_gpadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 11b048a..f5c61c0 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -279,4 +279,12 @@ config XILINX_XADC
 	  The driver can also be build as a module. If so, the module will be called
 	  xilinx-xadc.
 
+config AXP288_GPADC
+	tristate "X-Power AXP288 GPADC driver"
+	depends on MFD_AXP2XX
+	help
+	  Say yes here to have support for X-Power power management IC (PMIC) ADC
+	  device. Depending on platform configuration, this general purpose ADC can
+	  be used for sampling sensors such as thermal resisters.
+
 endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ad81b51..8bf0104 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_VF610_ADC) += vf610_adc.o
 obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
 xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
 obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
+obj-$(CONFIG_AXP288_GPADC) += axp288_gpadc.o
diff --git a/drivers/iio/adc/axp288_gpadc.c b/drivers/iio/adc/axp288_gpadc.c
new file mode 100644
index 0000000..7ca6bbf
--- /dev/null
+++ b/drivers/iio/adc/axp288_gpadc.c
@@ -0,0 +1,250 @@
+/*
+ * axp288_gpadc.c - Xpower AXP288 PMIC GPADC Driver
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp2xx.h>
+#include <linux/platform_device.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#define ADC_EN_MASK			0xF1
+#define ADC_TS_PIN_GPADC                0xF2
+#define ADC_TS_PIN_ON                   0xF3
+
+struct gpadc_info {
+	unsigned int irq;
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+#define ADC_CHANNEL(_type, _channel, _address)	        \
+	{								\
+		.indexed = 1,						\
+		.type = _type,						\
+		.channel = _channel,					\
+		.address = _address,					\
+		.datasheet_name = "CH"#_channel,			\
+		.scan_index = _channel,					\
+		.scan_type = {						\
+			.sign = 'u',					\
+			.realbits = 12,					\
+			.storagebits = 32,				\
+			.endianness = IIO_LE,				\
+		},							\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	}
+
+static const struct iio_chan_spec const axp288_adc_channels[] = {
+	ADC_CHANNEL(IIO_TEMP, 0, AXP288_TS_ADC_H),
+	ADC_CHANNEL(IIO_TEMP, 1, AXP288_PMIC_ADC_H),
+	ADC_CHANNEL(IIO_TEMP, 2, AXP288_GP_ADC_H),
+	ADC_CHANNEL(IIO_CURRENT, 3, AXP20X_BATT_CHRG_I_H),
+	ADC_CHANNEL(IIO_CURRENT, 4, AXP20X_BATT_DISCHRG_I_H),
+	ADC_CHANNEL(IIO_VOLTAGE, 5, AXP20X_BATT_V_H),
+};
+
+#define ADC_MAP(_adc_channel_label,				\
+		     _consumer_dev_name,			\
+		     _consumer_channel)				\
+	{							\
+		.adc_channel_label = _adc_channel_label,	\
+		.consumer_dev_name = _consumer_dev_name,	\
+		.consumer_channel = _consumer_channel,		\
+	}
+
+/* for consumer drivers */
+static struct iio_map axp288_iio_default_maps[] = {
+	ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
+	ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
+	ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
+	ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
+	ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
+	ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
+	{},
+};
+
+static int axp288_adc_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long m)
+{
+	int ret;
+	struct gpadc_info *info = iio_priv(indio_dev);
+	unsigned int th, tl;
+
+	mutex_lock(&indio_dev->mlock);
+
+	/* special case for GPADC sample */
+	if (chan->address == AXP288_GP_ADC_H)
+		regmap_write(info->regmap, AXP288_ADC_TS_PIN_CTRL,
+			ADC_TS_PIN_GPADC);
+
+	ret = regmap_read(info->regmap, chan->address, &th);
+	if (ret) {
+		dev_err(&indio_dev->dev, "sample raw data high failed\n");
+		goto exit_done;
+	}
+
+	ret = regmap_read(info->regmap, chan->address + 1, &tl);
+	if (ret) {
+		dev_err(&indio_dev->dev, "sample raw data low failed\n");
+		goto exit_done;
+	}
+
+	*val = (th << 4) + ((tl >> 4) & 0x0F);
+	ret = IIO_VAL_INT;
+
+exit_done:
+	if (chan->address == AXP288_GP_ADC_H)
+		regmap_write(info->regmap, AXP288_ADC_TS_PIN_CTRL,
+			ADC_TS_PIN_ON);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int axp288_gpadc_enable(struct regmap *regmap, bool enable)
+{
+	unsigned int pin_on, adc_en;
+
+	if (enable) {
+		pin_on = ADC_TS_PIN_ON;
+		adc_en = ADC_EN_MASK;
+	} else {
+		pin_on = ~ADC_TS_PIN_ON;
+		adc_en = ~ADC_EN_MASK;
+	}
+	if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, pin_on))
+		return -EIO;
+
+	return regmap_write(regmap, AXP20X_ADC_EN1, ~ADC_EN_MASK);
+}
+
+static const struct iio_info axp288_iio_info = {
+	.read_raw = &axp288_adc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int axp288_gpadc_probe(struct platform_device *pdev)
+{
+	int err;
+	struct gpadc_info *info;
+	struct iio_dev *indio_dev;
+	struct axp2xx_dev *axp2xx = dev_get_drvdata(pdev->dev.parent);
+	int irq;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	info = iio_priv(indio_dev);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return irq;
+	}
+	info->irq = irq;
+	platform_set_drvdata(pdev, indio_dev);
+	info->regmap = axp2xx->regmap;
+	axp288_gpadc_enable(axp2xx->regmap, true);
+
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = pdev->name;
+	indio_dev->channels = axp288_adc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
+	indio_dev->info = &axp288_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	/* REVISIT: override default map with platform data */
+	err = iio_map_array_register(indio_dev, axp288_iio_default_maps);
+	if (err)
+		goto err_disable_dev;
+
+	err = iio_device_register(indio_dev);
+	if (err < 0) {
+		dev_err(&pdev->dev, "unable to register iio device\n");
+		goto err_array_unregister;
+	}
+	return 0;
+
+err_array_unregister:
+	iio_map_array_unregister(indio_dev);
+err_disable_dev:
+	axp288_gpadc_enable(axp2xx->regmap, false);
+	return err;
+}
+
+static int axp288_gpadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	iio_device_unregister(indio_dev);
+	iio_map_array_unregister(indio_dev);
+
+	return 0;
+}
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+static int axp288_gpadc_suspend(struct device *dev)
+{
+	int ret;
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct gpadc_info *info = iio_priv(indio_dev);
+
+	mutex_lock(&indio_dev->mlock);
+	ret = axp288_gpadc_enable(info->regmap, false);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int axp288_gpadc_resume(struct device *dev)
+{
+	int ret;
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct gpadc_info *info = iio_priv(indio_dev);
+
+	mutex_lock(&indio_dev->mlock);
+	ret = axp288_gpadc_enable(info->regmap, true);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(axp288_gpadc_pm_ops, axp288_gpadc_suspend,
+			axp288_gpadc_resume, NULL);
+
+static struct platform_driver axp288_gpadc_driver = {
+	.probe = axp288_gpadc_probe,
+	.remove = axp288_gpadc_remove,
+	.driver = {
+		.name = "axp288_adc",
+		.owner = THIS_MODULE,
+		.pm = &axp288_gpadc_pm_ops,
+	},
+};
+
+module_platform_driver(axp288_gpadc_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
+MODULE_DESCRIPTION("Dollar Cove Xpower AXP288 General Purpose ADC Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic
  2014-09-08 22:24 ` [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic Jacob Pan
@ 2014-09-09  7:37   ` Maxime Ripard
  2014-09-09 12:45     ` Jacob Pan
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Ripard @ 2014-09-09  7:37 UTC (permalink / raw)
  To: Jacob Pan
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood, Mark Brown,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

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

Hi Jacob,

I think it would have been nice to have CC'd Carlo Caione, the
original writer of the driver on this.

On Mon, Sep 08, 2014 at 03:24:04PM -0700, Jacob Pan wrote:
> XPower AXP288 is a customized PMIC for Intel Baytrail-CR platforms. Similar
> to AXP202/209, AXP288 comes with USB charger, more LDO and BUCK channels, and
> AD converter. It also provides extended status and interrupt reporting
> capabilities than the devices supported in axp20x.c.
> 
> In addition to feature extension, this patch also adds ACPI binding for
> enumeration and hooks for ACPI custom operational region handlers.
> 
> Files and common data structures have been renamed from axp20x to axp2xx
> in order to suit the extended scope of devices.
> 
> This consolidated driver should support more Xpower PMICs in both device
> tree and ACPI based platforms.
> 
> Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> ---
>  drivers/mfd/axp2xx.c       | 424 +++++++++++++++++++++++++++++++++++----------
>  include/linux/mfd/axp2xx.h |  57 +++++-
>  2 files changed, 389 insertions(+), 92 deletions(-)
> 
> diff --git a/drivers/mfd/axp2xx.c b/drivers/mfd/axp2xx.c
> index c534443..cf7ed16 100644
> --- a/drivers/mfd/axp2xx.c
> +++ b/drivers/mfd/axp2xx.c
> @@ -1,10 +1,14 @@
>  /*
> - * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
> + * axp2xx.c - MFD core driver for the X-Powers AXP202, AXP209, and AXP288

Could you do the s/axp20x/axp2xx/ in the first patch? It would make
more sense to have it there, and reduce the "noise" in this patch.

>   *
>   * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
>   * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
>   * as well as 4 configurable GPIOs.
>   *
> + * AXP288 is a customized PMIC for Intel Baytrail CR platform. Similar to AXP20x
> + * it comes with USB charger, more LDO, BUCK channels, and status reporting
> + * capabilities.
> + *

Also, I'm not very convinced that maintaining the list of the
supported AXP chips is very future proof. We have at least 3 other
variants that we know of to support (AXP221, AXP223 and
AXP806/809). This would end up in a huge list :)

>   * Author: Carlo Caione <carlo@caione.org>
>   *
>   * This program is free software; you can redistribute it and/or modify
> @@ -25,9 +29,14 @@
>  #include <linux/mfd/core.h>
>  #include <linux/of_device.h>
>  #include <linux/of_irq.h>
> +#include <linux/acpi.h>
>  
>  #define AXP20X_OFF	0x80
>  
> +static struct mfd_cell *axp2xx_cells;
> +static int axp2xx_nr_cells;
> +static struct regmap_config *regmap_cfg;
> +
>  static const struct regmap_range axp20x_writeable_ranges[] = {
>  	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
>  	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
> @@ -47,6 +56,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
>  	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
>  };
>  
> +static const struct regmap_range axp288_writeable_ranges[] = {
> +	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
> +	regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
> +};
> +
> +static const struct regmap_range axp288_volatile_ranges[] = {
> +	regmap_reg_range(AXP20X_IRQ1_EN,  AXP20X_IPSOUT_V_HIGH_L),
> +};
> +
> +static const struct regmap_access_table axp288_writeable_table = {
> +	.yes_ranges	= axp288_writeable_ranges,
> +	.n_yes_ranges	= ARRAY_SIZE(axp288_writeable_ranges),
> +};
> +
> +static const struct regmap_access_table axp288_volatile_table = {
> +	.yes_ranges	= axp288_volatile_ranges,
> +	.n_yes_ranges	= ARRAY_SIZE(axp288_volatile_ranges),
> +};
> +
>  static struct resource axp20x_pek_resources[] = {
>  	{
>  		.name	= "PEK_DBR",
> @@ -61,7 +89,40 @@ static struct resource axp20x_pek_resources[] = {
>  	},
>  };
>  
> -static const struct regmap_config axp20x_regmap_config = {
> +static struct resource axp288_battery_resources[] = {
> +	{
> +		.start = AXP288_IRQ_QWBTU,
> +		.end   = AXP288_IRQ_QWBTU,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_WBTU,
> +		.end   = AXP288_IRQ_WBTU,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_QWBTO,
> +		.end   = AXP288_IRQ_QWBTO,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_WBTO,
> +		.end   = AXP288_IRQ_WBTO,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_WL2,
> +		.end   = AXP288_IRQ_WL2,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_WL1,
> +		.end   = AXP288_IRQ_WL1,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct regmap_config axp20x_regmap_config = {
>  	.reg_bits	= 8,
>  	.val_bits	= 8,
>  	.wr_table	= &axp20x_writeable_table,
> @@ -70,47 +131,96 @@ static const struct regmap_config axp20x_regmap_config = {
>  	.cache_type	= REGCACHE_RBTREE,
>  };
>  
> -#define AXP20X_IRQ(_irq, _off, _mask) \
> -	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
> +static struct regmap_config axp288_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.wr_table	= &axp288_writeable_table,
> +	.volatile_table	= &axp288_volatile_table,
> +	.max_register	= AXP288_FG_TUNE5,
> +	.cache_type	= REGCACHE_RBTREE,
> +};
> +
> +#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask)			\
> +	[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
>  
>  static const struct regmap_irq axp20x_regmap_irqs[] = {
> -	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
> -	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
> -	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
> -	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
> -	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
> -	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
> -	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
> -	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
> -	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
> -	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
> -	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
> -	AXP20X_IRQ(CHARG,		1, 3),
> -	AXP20X_IRQ(CHARG_DONE,		1, 2),
> -	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
> -	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
> -	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
> -	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
> -	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
> -	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
> -	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
> -	AXP20X_IRQ(PEK_SHORT,		2, 1),
> -	AXP20X_IRQ(PEK_LONG,		2, 0),
> -	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
> -	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
> -	AXP20X_IRQ(VBUS_VALID,		3, 5),
> -	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
> -	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
> -	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
> -	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
> -	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
> -	AXP20X_IRQ(TIMER,		4, 7),
> -	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
> -	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
> -	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
> -	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
> -	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
> -	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
> +	INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V,		0, 7),
> +	INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN,		0, 6),
> +	INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL,	        0, 5),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,		0, 4),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,		0, 3),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,	        0, 2),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW,		0, 1),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,		1, 7),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,	        1, 6),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE,	1, 5),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE,	1, 4),
> +	INIT_REGMAP_IRQ(AXP20X, CHARG,		        1, 3),
> +	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,		1, 2),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH,	        1, 1),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW,	        1, 0),
> +	INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH,	        2, 7),
> +	INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW,		2, 6),
> +	INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG,	        2, 5),
> +	INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG,	        2, 4),
> +	INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG,	        2, 3),
> +	INIT_REGMAP_IRQ(AXP20X, PEK_SHORT,		2, 1),
> +	INIT_REGMAP_IRQ(AXP20X, PEK_LONG,		2, 0),
> +	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON,		3, 7),
> +	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF,	        3, 6),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_VALID,		3, 5),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID,	        3, 4),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID,	3, 3),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END,	        3, 2),
> +	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1,	        3, 1),
> +	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2,	        3, 0),
> +	INIT_REGMAP_IRQ(AXP20X, TIMER,		        4, 7),
> +	INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE,	        4, 6),
> +	INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE,	        4, 5),
> +	INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT,		4, 3),
> +	INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT,		4, 2),
> +	INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT,		4, 1),
> +	INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT,		4, 0),
> +};
> +
> +/* some IRQs are compatible with axp20x models */
> +static const struct regmap_irq axp288_regmap_irqs[] = {
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,           0, 2),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,            0, 3),
> +	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,            0, 4),
> +
> +	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,             1, 2),
> +	INIT_REGMAP_IRQ(AXP20X, CHARG,                  1, 3),
> +	INIT_REGMAP_IRQ(AXP288, SAFE_QUIT,              1, 4),
> +	INIT_REGMAP_IRQ(AXP288, SAFE_ENTER,             1, 5),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,           1, 6),
> +	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,            1, 7),
> +
> +	INIT_REGMAP_IRQ(AXP288, QWBTU,                  2, 0),
> +	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 1),
> +	INIT_REGMAP_IRQ(AXP288, QWBTO,                  2, 2),
> +	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 3),
> +	INIT_REGMAP_IRQ(AXP288, QCBTU,                  2, 4),
> +	INIT_REGMAP_IRQ(AXP288, CBTU,                   2, 5),
> +	INIT_REGMAP_IRQ(AXP288, QCBTO,                  2, 6),
> +	INIT_REGMAP_IRQ(AXP288, CBTO,                   2, 7),
> +
> +	INIT_REGMAP_IRQ(AXP288, WL2,                    3, 0),
> +	INIT_REGMAP_IRQ(AXP288, WL1,                    3, 1),
> +	INIT_REGMAP_IRQ(AXP288, GPADC,                  3, 2),
> +	INIT_REGMAP_IRQ(AXP288, OT,                     3, 7),
> +
> +	INIT_REGMAP_IRQ(AXP288, GPIO0,                  4, 0),
> +	INIT_REGMAP_IRQ(AXP288, GPIO1,                  4, 1),
> +	INIT_REGMAP_IRQ(AXP288, POKO,                   4, 2),
> +	INIT_REGMAP_IRQ(AXP288, POKL,                   4, 3),
> +	INIT_REGMAP_IRQ(AXP288, POKS,                   4, 4),
> +	INIT_REGMAP_IRQ(AXP288, POKN,                   4, 5),
> +	INIT_REGMAP_IRQ(AXP288, POKP,                   4, 6),
> +	INIT_REGMAP_IRQ(AXP20X, TIMER,                  4, 7),
> +
> +	INIT_REGMAP_IRQ(AXP288, MV_CHNG,                5, 0),
> +	INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG,            5, 1),
>  };
>  
>  static const struct of_device_id axp20x_of_match[] = {
> @@ -123,19 +233,26 @@ MODULE_DEVICE_TABLE(of, axp20x_of_match);
>  /*
>   * This is useless for OF-enabled devices, but it is needed by I2C subsystem
>   */
> -static const struct i2c_device_id axp20x_i2c_id[] = {
> +static const struct i2c_device_id axp2xx_i2c_id[] = {
>  	{ },
>  };
> -MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> +MODULE_DEVICE_TABLE(i2c, axp2xx_i2c_id);
>  
> -static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
> -	.name			= "axp20x_irq_chip",
> +static struct acpi_device_id axp2xx_acpi_match[] = {
> +	{
> +		.id = "INT33F4",
> +		.driver_data = (kernel_ulong_t)AXP288_ID,
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(acpi, axp2xx_acpi_match);
> +
> +/* common irq chip attributes only */
> +static struct regmap_irq_chip axp2xx_regmap_irq_chip = {
> +	.name			= "axp2xx_irq_chip",
>  	.status_base		= AXP20X_IRQ1_STATE,
>  	.ack_base		= AXP20X_IRQ1_STATE,
>  	.mask_base		= AXP20X_IRQ1_EN,
> -	.num_regs		= 5,
> -	.irqs			= axp20x_regmap_irqs,
> -	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
>  	.mask_invert		= true,
>  	.init_ack_masked	= true,
>  };
> @@ -161,98 +278,223 @@ static struct mfd_cell axp20x_cells[] = {
>  	},
>  };
>  
> -static struct axp20x_dev *axp20x_pm_power_off;
> -static void axp20x_power_off(void)
> +static struct resource axp288_adc_resources[] = {
> +	{
> +		.name	= "GPADC",
> +		.start = AXP288_IRQ_GPADC,
> +		.end   = AXP288_IRQ_GPADC,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct resource axp288_charger_resources[] = {
> +	{
> +		.start = AXP288_IRQ_OV,
> +		.end   = AXP288_IRQ_OV,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_DONE,
> +		.end   = AXP288_IRQ_DONE,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_CHARGING,
> +		.end   = AXP288_IRQ_CHARGING,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_SAFE_QUIT,
> +		.end   = AXP288_IRQ_SAFE_QUIT,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_SAFE_ENTER,
> +		.end   = AXP288_IRQ_SAFE_ENTER,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_QCBTU,
> +		.end   = AXP288_IRQ_QCBTU,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_CBTU,
> +		.end   = AXP288_IRQ_CBTU,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_QCBTO,
> +		.end   = AXP288_IRQ_QCBTO,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.start = AXP288_IRQ_CBTO,
> +		.end   = AXP288_IRQ_CBTO,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct mfd_cell axp288_cells[] = {
> +	{
> +		.name = "axp288_adc",
> +		.num_resources = ARRAY_SIZE(axp288_adc_resources),
> +		.resources = axp288_adc_resources,
> +	},
> +	{
> +		.name = "axp288_charger",
> +		.num_resources = ARRAY_SIZE(axp288_charger_resources),
> +		.resources = axp288_charger_resources,
> +	},
> +	{
> +		.name = "axp288_battery",
> +		.num_resources = ARRAY_SIZE(axp288_battery_resources),
> +		.resources = axp288_battery_resources,
> +	},
> +	{
> +		.name = "axp288_acpi_opregion",
> +	},
> +};
> +
> +static struct axp2xx_dev *axp2xx_pm_power_off;
> +static void axp2xx_power_off(void)
>  {
> -	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
> +	if (axp2xx_pm_power_off->variant == AXP288_ID)
> +		return;
> +	regmap_write(axp2xx_pm_power_off->regmap, AXP20X_OFF_CTRL,
>  		     AXP20X_OFF);
>  }
>  
> -static int axp20x_i2c_probe(struct i2c_client *i2c,
> -			 const struct i2c_device_id *id)
> +static int axp2xx_match_device(struct axp2xx_dev *axp2xx, struct device *dev)
>  {
> -	struct axp20x_dev *axp20x;
> +	const struct acpi_device_id *acpi_id;
>  	const struct of_device_id *of_id;
> -	int ret;
>  
> -	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
> -	if (!axp20x)
> -		return -ENOMEM;
> +	of_id = of_match_device(axp2xx_of_match, dev);
> +	if (of_id) {
> +		axp2xx->variant = (long) of_id->data;
> +		goto found_match;
> +	}
>  
> -	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> -	if (!of_id) {
> -		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
> +	acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
> +	if (!acpi_id || !acpi_id->driver_data) {
> +		dev_err(dev, "Unable to setup AXP2XX ACPI data\n");
>  		return -ENODEV;
>  	}
> -	axp20x->variant = (long) of_id->data;
> +	axp2xx->variant = (long) acpi_id->driver_data;

Shouldn't that be in the if statement above? I guess acpi_id will be
null on a DT-based system.

> +
> +found_match:
> +	switch (axp2xx->variant) {
> +	case AXP202_ID:
> +	case AXP209_ID:
> +		dev_dbg(dev, "AXP2xx variant AXP202/209 found\n");
> +		axp2xx_nr_cells = ARRAY_SIZE(axp20x_cells);
> +		axp2xx_cells = axp20x_cells;
> +		regmap_cfg = &axp20x_regmap_config;
> +		axp2xx_regmap_irq_chip.num_regs	= 5;
> +		axp2xx_regmap_irq_chip.irqs = axp20x_regmap_irqs;
> +		axp2xx_regmap_irq_chip.num_irqs	=
> +			ARRAY_SIZE(axp20x_regmap_irqs);
> +		break;
> +	case AXP288_ID:
> +		dev_dbg(dev, "AXP2xx variant AXP288 found\n");
> +		axp2xx_cells = axp288_cells;
> +		axp2xx_nr_cells = ARRAY_SIZE(axp288_cells);
> +		axp2xx_regmap_irq_chip.irqs = axp288_regmap_irqs;
> +		axp2xx_regmap_irq_chip.num_irqs	=
> +			ARRAY_SIZE(axp288_regmap_irqs);
> +		axp2xx_regmap_irq_chip.num_regs	= 6;
> +		regmap_cfg = &axp288_regmap_config;
> +		break;
> +	default:
> +		dev_err(dev, "unsupported AXP2XX ID %lu\n", axp2xx->variant);
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> +static int axp2xx_i2c_probe(struct i2c_client *i2c,
> +			const struct i2c_device_id *id)
> +{
> +	struct axp2xx_dev *axp2xx;
> +	int ret;
>  
> -	axp20x->i2c_client = i2c;
> -	axp20x->dev = &i2c->dev;
> -	dev_set_drvdata(axp20x->dev, axp20x);
> +	axp2xx = devm_kzalloc(&i2c->dev, sizeof(*axp2xx), GFP_KERNEL);
> +	if (!axp2xx)
> +		return -ENOMEM;
> +
> +	ret = axp2xx_match_device(axp2xx, &i2c->dev);
> +	if (ret)
> +		return ret;
> +	axp2xx->i2c_client = i2c;
> +	axp2xx->dev = &i2c->dev;
> +	dev_set_drvdata(axp2xx->dev, axp2xx);
>  
> -	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
> -	if (IS_ERR(axp20x->regmap)) {
> -		ret = PTR_ERR(axp20x->regmap);
> +	axp2xx->regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
> +	if (IS_ERR(axp2xx->regmap)) {
> +		ret = PTR_ERR(axp2xx->regmap);
>  		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
>  		return ret;
>  	}
>  
> -	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
> +	ret = regmap_add_irq_chip(axp2xx->regmap, i2c->irq,
>  				  IRQF_ONESHOT | IRQF_SHARED, -1,
> -				  &axp20x_regmap_irq_chip,
> -				  &axp20x->regmap_irqc);
> +				  &axp2xx_regmap_irq_chip,
> +				  &axp2xx->regmap_irqc);
>  	if (ret) {
>  		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
>  		return ret;
>  	}
>  
> -	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
> -			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
> +	ret = mfd_add_devices(axp2xx->dev, -1, axp2xx_cells,
> +			axp2xx_nr_cells, NULL, 0, NULL);
>  
>  	if (ret) {
>  		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
> -		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
> +		regmap_del_irq_chip(i2c->irq, axp2xx->regmap_irqc);
>  		return ret;
>  	}
>  
>  	if (!pm_power_off) {
> -		axp20x_pm_power_off = axp20x;
> -		pm_power_off = axp20x_power_off;
> +		axp2xx_pm_power_off = axp2xx;
> +		pm_power_off = axp2xx_power_off;
>  	}
>  
> -	dev_info(&i2c->dev, "AXP20X driver loaded\n");
> +	dev_info(&i2c->dev, "AXP2XX driver loaded\n");
>  
>  	return 0;
>  }
>  
> -static int axp20x_i2c_remove(struct i2c_client *i2c)
> +static int axp2xx_i2c_remove(struct i2c_client *i2c)
>  {
> -	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
> +	struct axp2xx_dev *axp2xx = i2c_get_clientdata(i2c);
>  
> -	if (axp20x == axp20x_pm_power_off) {
> -		axp20x_pm_power_off = NULL;
> +	if (axp2xx == axp2xx_pm_power_off) {
> +		axp2xx_pm_power_off = NULL;
>  		pm_power_off = NULL;
>  	}
>  
> -	mfd_remove_devices(axp20x->dev);
> -	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
> +	mfd_remove_devices(axp2xx->dev);
> +	regmap_del_irq_chip(axp2xx->i2c_client->irq, axp2xx->regmap_irqc);
>  
>  	return 0;
>  }
>  
> -static struct i2c_driver axp20x_i2c_driver = {
> +static struct i2c_driver axp2xx_i2c_driver = {
>  	.driver = {
> -		.name	= "axp20x",
> +		.name	= "axp2xx",
>  		.owner	= THIS_MODULE,
> -		.of_match_table	= of_match_ptr(axp20x_of_match),
> +		.of_match_table	= of_match_ptr(axp2xx_of_match),
> +		.acpi_match_table = ACPI_PTR(axp2xx_acpi_match),
>  	},
> -	.probe		= axp20x_i2c_probe,
> -	.remove		= axp20x_i2c_remove,
> -	.id_table	= axp20x_i2c_id,
> +	.probe		= axp2xx_i2c_probe,
> +	.remove		= axp2xx_i2c_remove,
> +	.id_table	= axp2xx_i2c_id,
>  };
>  
> -module_i2c_driver(axp20x_i2c_driver);
> +module_i2c_driver(axp2xx_i2c_driver);
>  
> -MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
> +MODULE_DESCRIPTION("PMIC MFD core driver for AXP2XX");
>  MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/axp2xx.h b/include/linux/mfd/axp2xx.h
> index d0e31a2..672f048 100644
> --- a/include/linux/mfd/axp2xx.h
> +++ b/include/linux/mfd/axp2xx.h
> @@ -14,6 +14,8 @@
>  enum {
>  	AXP202_ID = 0,
>  	AXP209_ID,
> +	AXP288_ID,
> +	NR_AXP288_VARIANTS,

Can't that be a more generic name? Something like NR_AXP2XX instead?

Also, could you put me in CC in the later iterations of the patches?

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/4] mfd/axp20x: rename files to support more devices
  2014-09-08 22:24 ` [PATCH 1/4] mfd/axp20x: rename files to support more devices Jacob Pan
@ 2014-09-09  8:11   ` Lee Jones
  0 siblings, 0 replies; 14+ messages in thread
From: Lee Jones @ 2014-09-09  8:11 UTC (permalink / raw)
  To: Jacob Pan
  Cc: IIO, LKML, DEVICE TREE, Srinivas Pandruvada, Aaron Lu, Alan Cox,
	Jean Delvare, Samuel Ortiz, Liam Girdwood, Mark Brown,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

On Mon, 08 Sep 2014, Jacob Pan wrote:

> More XPowers PMIC devices can be supported by extending this driver, so
> rename it to axp2xx to cover axp288 variant.
> 
> Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> ---
>  drivers/mfd/Kconfig        |   7 +-
>  drivers/mfd/Makefile       |   2 +-
>  drivers/mfd/axp20x.c       | 258 ---------------------------------------------
>  drivers/mfd/axp2xx.c       | 258 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/axp20x.h | 180 -------------------------------
>  include/linux/mfd/axp2xx.h | 180 +++++++++++++++++++++++++++++++
>  6 files changed, 443 insertions(+), 442 deletions(-)
>  delete mode 100644 drivers/mfd/axp20x.c
>  create mode 100644 drivers/mfd/axp2xx.c
>  delete mode 100644 include/linux/mfd/axp20x.h
>  create mode 100644 include/linux/mfd/axp2xx.h

Please resubmit using `git format-patch -M`

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index de5abf2..42a70a3 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -67,14 +67,15 @@ config MFD_BCM590XX
>  	help
>  	  Support for the BCM590xx PMUs from Broadcom
>  
> -config MFD_AXP20X
> -	bool "X-Powers AXP20X"
> +config MFD_AXP2XX
> +	bool "X-Powers AXP2XX"
>  	select MFD_CORE
>  	select REGMAP_I2C
>  	select REGMAP_IRQ
>  	depends on I2C=y
>  	help
> -	  If you say Y here you get support for the X-Powers AXP202 and AXP209.
> +	  If you say Y here you get support for the X-Powers AXP202, AXP209 and
> +	  AXP288 power management IC (PMIC).
>  	  This driver include only the core APIs. You have to select individual
>  	  components like regulators or the PEK (Power Enable Key) under the
>  	  corresponding menus.
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f001487..55d76b3 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -103,7 +103,7 @@ obj-$(CONFIG_PMIC_DA9052)	+= da9052-irq.o
>  obj-$(CONFIG_PMIC_DA9052)	+= da9052-core.o
>  obj-$(CONFIG_MFD_DA9052_SPI)	+= da9052-spi.o
>  obj-$(CONFIG_MFD_DA9052_I2C)	+= da9052-i2c.o
> -obj-$(CONFIG_MFD_AXP20X)	+= axp20x.o
> +obj-$(CONFIG_MFD_AXP2XX)	+= axp2xx.o
>  
>  obj-$(CONFIG_MFD_LP3943)	+= lp3943.o
>  obj-$(CONFIG_MFD_LP8788)	+= lp8788.o lp8788-irq.o
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> deleted file mode 100644
> index dee6539..0000000
> --- a/drivers/mfd/axp20x.c
> +++ /dev/null
> @@ -1,258 +0,0 @@
> -/*
> - * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
> - *
> - * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
> - * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
> - * as well as 4 configurable GPIOs.
> - *
> - * Author: Carlo Caione <carlo@caione.org>
> - *
> - * 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/err.h>
> -#include <linux/i2c.h>
> -#include <linux/interrupt.h>
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/pm_runtime.h>
> -#include <linux/regmap.h>
> -#include <linux/slab.h>
> -#include <linux/regulator/consumer.h>
> -#include <linux/mfd/axp20x.h>
> -#include <linux/mfd/core.h>
> -#include <linux/of_device.h>
> -#include <linux/of_irq.h>
> -
> -#define AXP20X_OFF	0x80
> -
> -static const struct regmap_range axp20x_writeable_ranges[] = {
> -	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
> -	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
> -};
> -
> -static const struct regmap_range axp20x_volatile_ranges[] = {
> -	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
> -};
> -
> -static const struct regmap_access_table axp20x_writeable_table = {
> -	.yes_ranges	= axp20x_writeable_ranges,
> -	.n_yes_ranges	= ARRAY_SIZE(axp20x_writeable_ranges),
> -};
> -
> -static const struct regmap_access_table axp20x_volatile_table = {
> -	.yes_ranges	= axp20x_volatile_ranges,
> -	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
> -};
> -
> -static struct resource axp20x_pek_resources[] = {
> -	{
> -		.name	= "PEK_DBR",
> -		.start	= AXP20X_IRQ_PEK_RIS_EDGE,
> -		.end	= AXP20X_IRQ_PEK_RIS_EDGE,
> -		.flags	= IORESOURCE_IRQ,
> -	}, {
> -		.name	= "PEK_DBF",
> -		.start	= AXP20X_IRQ_PEK_FAL_EDGE,
> -		.end	= AXP20X_IRQ_PEK_FAL_EDGE,
> -		.flags	= IORESOURCE_IRQ,
> -	},
> -};
> -
> -static const struct regmap_config axp20x_regmap_config = {
> -	.reg_bits	= 8,
> -	.val_bits	= 8,
> -	.wr_table	= &axp20x_writeable_table,
> -	.volatile_table	= &axp20x_volatile_table,
> -	.max_register	= AXP20X_FG_RES,
> -	.cache_type	= REGCACHE_RBTREE,
> -};
> -
> -#define AXP20X_IRQ(_irq, _off, _mask) \
> -	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
> -
> -static const struct regmap_irq axp20x_regmap_irqs[] = {
> -	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
> -	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
> -	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
> -	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
> -	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
> -	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
> -	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
> -	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
> -	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
> -	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
> -	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
> -	AXP20X_IRQ(CHARG,		1, 3),
> -	AXP20X_IRQ(CHARG_DONE,		1, 2),
> -	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
> -	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
> -	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
> -	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
> -	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
> -	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
> -	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
> -	AXP20X_IRQ(PEK_SHORT,		2, 1),
> -	AXP20X_IRQ(PEK_LONG,		2, 0),
> -	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
> -	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
> -	AXP20X_IRQ(VBUS_VALID,		3, 5),
> -	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
> -	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
> -	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
> -	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
> -	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
> -	AXP20X_IRQ(TIMER,		4, 7),
> -	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
> -	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
> -	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
> -	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
> -	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
> -	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
> -};
> -
> -static const struct of_device_id axp20x_of_match[] = {
> -	{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
> -	{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(of, axp20x_of_match);
> -
> -/*
> - * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> - */
> -static const struct i2c_device_id axp20x_i2c_id[] = {
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> -
> -static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
> -	.name			= "axp20x_irq_chip",
> -	.status_base		= AXP20X_IRQ1_STATE,
> -	.ack_base		= AXP20X_IRQ1_STATE,
> -	.mask_base		= AXP20X_IRQ1_EN,
> -	.num_regs		= 5,
> -	.irqs			= axp20x_regmap_irqs,
> -	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
> -	.mask_invert		= true,
> -	.init_ack_masked	= true,
> -};
> -
> -static const char * const axp20x_supplies[] = {
> -	"acin",
> -	"vin2",
> -	"vin3",
> -	"ldo24in",
> -	"ldo3in",
> -	"ldo5in",
> -};
> -
> -static struct mfd_cell axp20x_cells[] = {
> -	{
> -		.name			= "axp20x-pek",
> -		.num_resources		= ARRAY_SIZE(axp20x_pek_resources),
> -		.resources		= axp20x_pek_resources,
> -	}, {
> -		.name			= "axp20x-regulator",
> -		.parent_supplies	= axp20x_supplies,
> -		.num_parent_supplies	= ARRAY_SIZE(axp20x_supplies),
> -	},
> -};
> -
> -static struct axp20x_dev *axp20x_pm_power_off;
> -static void axp20x_power_off(void)
> -{
> -	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
> -		     AXP20X_OFF);
> -}
> -
> -static int axp20x_i2c_probe(struct i2c_client *i2c,
> -			 const struct i2c_device_id *id)
> -{
> -	struct axp20x_dev *axp20x;
> -	const struct of_device_id *of_id;
> -	int ret;
> -
> -	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
> -	if (!axp20x)
> -		return -ENOMEM;
> -
> -	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> -	if (!of_id) {
> -		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
> -		return -ENODEV;
> -	}
> -	axp20x->variant = (long) of_id->data;
> -
> -	axp20x->i2c_client = i2c;
> -	axp20x->dev = &i2c->dev;
> -	dev_set_drvdata(axp20x->dev, axp20x);
> -
> -	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
> -	if (IS_ERR(axp20x->regmap)) {
> -		ret = PTR_ERR(axp20x->regmap);
> -		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
> -		return ret;
> -	}
> -
> -	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
> -				  IRQF_ONESHOT | IRQF_SHARED, -1,
> -				  &axp20x_regmap_irq_chip,
> -				  &axp20x->regmap_irqc);
> -	if (ret) {
> -		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
> -		return ret;
> -	}
> -
> -	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
> -			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
> -
> -	if (ret) {
> -		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
> -		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
> -		return ret;
> -	}
> -
> -	if (!pm_power_off) {
> -		axp20x_pm_power_off = axp20x;
> -		pm_power_off = axp20x_power_off;
> -	}
> -
> -	dev_info(&i2c->dev, "AXP20X driver loaded\n");
> -
> -	return 0;
> -}
> -
> -static int axp20x_i2c_remove(struct i2c_client *i2c)
> -{
> -	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
> -
> -	if (axp20x == axp20x_pm_power_off) {
> -		axp20x_pm_power_off = NULL;
> -		pm_power_off = NULL;
> -	}
> -
> -	mfd_remove_devices(axp20x->dev);
> -	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
> -
> -	return 0;
> -}
> -
> -static struct i2c_driver axp20x_i2c_driver = {
> -	.driver = {
> -		.name	= "axp20x",
> -		.owner	= THIS_MODULE,
> -		.of_match_table	= of_match_ptr(axp20x_of_match),
> -	},
> -	.probe		= axp20x_i2c_probe,
> -	.remove		= axp20x_i2c_remove,
> -	.id_table	= axp20x_i2c_id,
> -};
> -
> -module_i2c_driver(axp20x_i2c_driver);
> -
> -MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
> -MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/mfd/axp2xx.c b/drivers/mfd/axp2xx.c
> new file mode 100644
> index 0000000..c534443
> --- /dev/null
> +++ b/drivers/mfd/axp2xx.c
> @@ -0,0 +1,258 @@
> +/*
> + * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
> + *
> + * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
> + * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
> + * as well as 4 configurable GPIOs.
> + *
> + * Author: Carlo Caione <carlo@caione.org>
> + *
> + * 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/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/mfd/axp2xx.h>
> +#include <linux/mfd/core.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +
> +#define AXP20X_OFF	0x80
> +
> +static const struct regmap_range axp20x_writeable_ranges[] = {
> +	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
> +	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
> +};
> +
> +static const struct regmap_range axp20x_volatile_ranges[] = {
> +	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
> +};
> +
> +static const struct regmap_access_table axp20x_writeable_table = {
> +	.yes_ranges	= axp20x_writeable_ranges,
> +	.n_yes_ranges	= ARRAY_SIZE(axp20x_writeable_ranges),
> +};
> +
> +static const struct regmap_access_table axp20x_volatile_table = {
> +	.yes_ranges	= axp20x_volatile_ranges,
> +	.n_yes_ranges	= ARRAY_SIZE(axp20x_volatile_ranges),
> +};
> +
> +static struct resource axp20x_pek_resources[] = {
> +	{
> +		.name	= "PEK_DBR",
> +		.start	= AXP20X_IRQ_PEK_RIS_EDGE,
> +		.end	= AXP20X_IRQ_PEK_RIS_EDGE,
> +		.flags	= IORESOURCE_IRQ,
> +	}, {
> +		.name	= "PEK_DBF",
> +		.start	= AXP20X_IRQ_PEK_FAL_EDGE,
> +		.end	= AXP20X_IRQ_PEK_FAL_EDGE,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static const struct regmap_config axp20x_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.wr_table	= &axp20x_writeable_table,
> +	.volatile_table	= &axp20x_volatile_table,
> +	.max_register	= AXP20X_FG_RES,
> +	.cache_type	= REGCACHE_RBTREE,
> +};
> +
> +#define AXP20X_IRQ(_irq, _off, _mask) \
> +	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
> +
> +static const struct regmap_irq axp20x_regmap_irqs[] = {
> +	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
> +	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
> +	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
> +	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
> +	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
> +	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
> +	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
> +	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
> +	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
> +	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
> +	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
> +	AXP20X_IRQ(CHARG,		1, 3),
> +	AXP20X_IRQ(CHARG_DONE,		1, 2),
> +	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
> +	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
> +	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
> +	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
> +	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
> +	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
> +	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
> +	AXP20X_IRQ(PEK_SHORT,		2, 1),
> +	AXP20X_IRQ(PEK_LONG,		2, 0),
> +	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
> +	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
> +	AXP20X_IRQ(VBUS_VALID,		3, 5),
> +	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
> +	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
> +	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
> +	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
> +	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
> +	AXP20X_IRQ(TIMER,		4, 7),
> +	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
> +	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
> +	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
> +	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
> +	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
> +	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
> +};
> +
> +static const struct of_device_id axp20x_of_match[] = {
> +	{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
> +	{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, axp20x_of_match);
> +
> +/*
> + * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> + */
> +static const struct i2c_device_id axp20x_i2c_id[] = {
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> +
> +static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
> +	.name			= "axp20x_irq_chip",
> +	.status_base		= AXP20X_IRQ1_STATE,
> +	.ack_base		= AXP20X_IRQ1_STATE,
> +	.mask_base		= AXP20X_IRQ1_EN,
> +	.num_regs		= 5,
> +	.irqs			= axp20x_regmap_irqs,
> +	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
> +	.mask_invert		= true,
> +	.init_ack_masked	= true,
> +};
> +
> +static const char * const axp20x_supplies[] = {
> +	"acin",
> +	"vin2",
> +	"vin3",
> +	"ldo24in",
> +	"ldo3in",
> +	"ldo5in",
> +};
> +
> +static struct mfd_cell axp20x_cells[] = {
> +	{
> +		.name			= "axp20x-pek",
> +		.num_resources		= ARRAY_SIZE(axp20x_pek_resources),
> +		.resources		= axp20x_pek_resources,
> +	}, {
> +		.name			= "axp20x-regulator",
> +		.parent_supplies	= axp20x_supplies,
> +		.num_parent_supplies	= ARRAY_SIZE(axp20x_supplies),
> +	},
> +};
> +
> +static struct axp20x_dev *axp20x_pm_power_off;
> +static void axp20x_power_off(void)
> +{
> +	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
> +		     AXP20X_OFF);
> +}
> +
> +static int axp20x_i2c_probe(struct i2c_client *i2c,
> +			 const struct i2c_device_id *id)
> +{
> +	struct axp20x_dev *axp20x;
> +	const struct of_device_id *of_id;
> +	int ret;
> +
> +	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
> +	if (!axp20x)
> +		return -ENOMEM;
> +
> +	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> +	if (!of_id) {
> +		dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
> +		return -ENODEV;
> +	}
> +	axp20x->variant = (long) of_id->data;
> +
> +	axp20x->i2c_client = i2c;
> +	axp20x->dev = &i2c->dev;
> +	dev_set_drvdata(axp20x->dev, axp20x);
> +
> +	axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
> +	if (IS_ERR(axp20x->regmap)) {
> +		ret = PTR_ERR(axp20x->regmap);
> +		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
> +				  IRQF_ONESHOT | IRQF_SHARED, -1,
> +				  &axp20x_regmap_irq_chip,
> +				  &axp20x->regmap_irqc);
> +	if (ret) {
> +		dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
> +			      ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
> +
> +	if (ret) {
> +		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
> +		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
> +		return ret;
> +	}
> +
> +	if (!pm_power_off) {
> +		axp20x_pm_power_off = axp20x;
> +		pm_power_off = axp20x_power_off;
> +	}
> +
> +	dev_info(&i2c->dev, "AXP20X driver loaded\n");
> +
> +	return 0;
> +}
> +
> +static int axp20x_i2c_remove(struct i2c_client *i2c)
> +{
> +	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
> +
> +	if (axp20x == axp20x_pm_power_off) {
> +		axp20x_pm_power_off = NULL;
> +		pm_power_off = NULL;
> +	}
> +
> +	mfd_remove_devices(axp20x->dev);
> +	regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
> +
> +	return 0;
> +}
> +
> +static struct i2c_driver axp20x_i2c_driver = {
> +	.driver = {
> +		.name	= "axp20x",
> +		.owner	= THIS_MODULE,
> +		.of_match_table	= of_match_ptr(axp20x_of_match),
> +	},
> +	.probe		= axp20x_i2c_probe,
> +	.remove		= axp20x_i2c_remove,
> +	.id_table	= axp20x_i2c_id,
> +};
> +
> +module_i2c_driver(axp20x_i2c_driver);
> +
> +MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
> +MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
> deleted file mode 100644
> index d0e31a2..0000000
> --- a/include/linux/mfd/axp20x.h
> +++ /dev/null
> @@ -1,180 +0,0 @@
> -/*
> - * Functions and registers to access AXP20X power management chip.
> - *
> - * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
> - *
> - * 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 __LINUX_MFD_AXP20X_H
> -#define __LINUX_MFD_AXP20X_H
> -
> -enum {
> -	AXP202_ID = 0,
> -	AXP209_ID,
> -};
> -
> -#define AXP20X_DATACACHE(m)		(0x04 + (m))
> -
> -/* Power supply */
> -#define AXP20X_PWR_INPUT_STATUS		0x00
> -#define AXP20X_PWR_OP_MODE		0x01
> -#define AXP20X_USB_OTG_STATUS		0x02
> -#define AXP20X_PWR_OUT_CTRL		0x12
> -#define AXP20X_DCDC2_V_OUT		0x23
> -#define AXP20X_DCDC2_LDO3_V_SCAL	0x25
> -#define AXP20X_DCDC3_V_OUT		0x27
> -#define AXP20X_LDO24_V_OUT		0x28
> -#define AXP20X_LDO3_V_OUT		0x29
> -#define AXP20X_VBUS_IPSOUT_MGMT		0x30
> -#define AXP20X_V_OFF			0x31
> -#define AXP20X_OFF_CTRL			0x32
> -#define AXP20X_CHRG_CTRL1		0x33
> -#define AXP20X_CHRG_CTRL2		0x34
> -#define AXP20X_CHRG_BAK_CTRL		0x35
> -#define AXP20X_PEK_KEY			0x36
> -#define AXP20X_DCDC_FREQ		0x37
> -#define AXP20X_V_LTF_CHRG		0x38
> -#define AXP20X_V_HTF_CHRG		0x39
> -#define AXP20X_APS_WARN_L1		0x3a
> -#define AXP20X_APS_WARN_L2		0x3b
> -#define AXP20X_V_LTF_DISCHRG		0x3c
> -#define AXP20X_V_HTF_DISCHRG		0x3d
> -
> -/* Interrupt */
> -#define AXP20X_IRQ1_EN			0x40
> -#define AXP20X_IRQ2_EN			0x41
> -#define AXP20X_IRQ3_EN			0x42
> -#define AXP20X_IRQ4_EN			0x43
> -#define AXP20X_IRQ5_EN			0x44
> -#define AXP20X_IRQ1_STATE		0x48
> -#define AXP20X_IRQ2_STATE		0x49
> -#define AXP20X_IRQ3_STATE		0x4a
> -#define AXP20X_IRQ4_STATE		0x4b
> -#define AXP20X_IRQ5_STATE		0x4c
> -
> -/* ADC */
> -#define AXP20X_ACIN_V_ADC_H		0x56
> -#define AXP20X_ACIN_V_ADC_L		0x57
> -#define AXP20X_ACIN_I_ADC_H		0x58
> -#define AXP20X_ACIN_I_ADC_L		0x59
> -#define AXP20X_VBUS_V_ADC_H		0x5a
> -#define AXP20X_VBUS_V_ADC_L		0x5b
> -#define AXP20X_VBUS_I_ADC_H		0x5c
> -#define AXP20X_VBUS_I_ADC_L		0x5d
> -#define AXP20X_TEMP_ADC_H		0x5e
> -#define AXP20X_TEMP_ADC_L		0x5f
> -#define AXP20X_TS_IN_H			0x62
> -#define AXP20X_TS_IN_L			0x63
> -#define AXP20X_GPIO0_V_ADC_H		0x64
> -#define AXP20X_GPIO0_V_ADC_L		0x65
> -#define AXP20X_GPIO1_V_ADC_H		0x66
> -#define AXP20X_GPIO1_V_ADC_L		0x67
> -#define AXP20X_PWR_BATT_H		0x70
> -#define AXP20X_PWR_BATT_M		0x71
> -#define AXP20X_PWR_BATT_L		0x72
> -#define AXP20X_BATT_V_H			0x78
> -#define AXP20X_BATT_V_L			0x79
> -#define AXP20X_BATT_CHRG_I_H		0x7a
> -#define AXP20X_BATT_CHRG_I_L		0x7b
> -#define AXP20X_BATT_DISCHRG_I_H		0x7c
> -#define AXP20X_BATT_DISCHRG_I_L		0x7d
> -#define AXP20X_IPSOUT_V_HIGH_H		0x7e
> -#define AXP20X_IPSOUT_V_HIGH_L		0x7f
> -
> -/* Power supply */
> -#define AXP20X_DCDC_MODE		0x80
> -#define AXP20X_ADC_EN1			0x82
> -#define AXP20X_ADC_EN2			0x83
> -#define AXP20X_ADC_RATE			0x84
> -#define AXP20X_GPIO10_IN_RANGE		0x85
> -#define AXP20X_GPIO1_ADC_IRQ_RIS	0x86
> -#define AXP20X_GPIO1_ADC_IRQ_FAL	0x87
> -#define AXP20X_TIMER_CTRL		0x8a
> -#define AXP20X_VBUS_MON			0x8b
> -#define AXP20X_OVER_TMP			0x8f
> -
> -/* GPIO */
> -#define AXP20X_GPIO0_CTRL		0x90
> -#define AXP20X_LDO5_V_OUT		0x91
> -#define AXP20X_GPIO1_CTRL		0x92
> -#define AXP20X_GPIO2_CTRL		0x93
> -#define AXP20X_GPIO20_SS		0x94
> -#define AXP20X_GPIO3_CTRL		0x95
> -
> -/* Battery */
> -#define AXP20X_CHRG_CC_31_24		0xb0
> -#define AXP20X_CHRG_CC_23_16		0xb1
> -#define AXP20X_CHRG_CC_15_8		0xb2
> -#define AXP20X_CHRG_CC_7_0		0xb3
> -#define AXP20X_DISCHRG_CC_31_24		0xb4
> -#define AXP20X_DISCHRG_CC_23_16		0xb5
> -#define AXP20X_DISCHRG_CC_15_8		0xb6
> -#define AXP20X_DISCHRG_CC_7_0		0xb7
> -#define AXP20X_CC_CTRL			0xb8
> -#define AXP20X_FG_RES			0xb9
> -
> -/* Regulators IDs */
> -enum {
> -	AXP20X_LDO1 = 0,
> -	AXP20X_LDO2,
> -	AXP20X_LDO3,
> -	AXP20X_LDO4,
> -	AXP20X_LDO5,
> -	AXP20X_DCDC2,
> -	AXP20X_DCDC3,
> -	AXP20X_REG_ID_MAX,
> -};
> -
> -/* IRQs */
> -enum {
> -	AXP20X_IRQ_ACIN_OVER_V = 1,
> -	AXP20X_IRQ_ACIN_PLUGIN,
> -	AXP20X_IRQ_ACIN_REMOVAL,
> -	AXP20X_IRQ_VBUS_OVER_V,
> -	AXP20X_IRQ_VBUS_PLUGIN,
> -	AXP20X_IRQ_VBUS_REMOVAL,
> -	AXP20X_IRQ_VBUS_V_LOW,
> -	AXP20X_IRQ_BATT_PLUGIN,
> -	AXP20X_IRQ_BATT_REMOVAL,
> -	AXP20X_IRQ_BATT_ENT_ACT_MODE,
> -	AXP20X_IRQ_BATT_EXIT_ACT_MODE,
> -	AXP20X_IRQ_CHARG,
> -	AXP20X_IRQ_CHARG_DONE,
> -	AXP20X_IRQ_BATT_TEMP_HIGH,
> -	AXP20X_IRQ_BATT_TEMP_LOW,
> -	AXP20X_IRQ_DIE_TEMP_HIGH,
> -	AXP20X_IRQ_CHARG_I_LOW,
> -	AXP20X_IRQ_DCDC1_V_LONG,
> -	AXP20X_IRQ_DCDC2_V_LONG,
> -	AXP20X_IRQ_DCDC3_V_LONG,
> -	AXP20X_IRQ_PEK_SHORT = 22,
> -	AXP20X_IRQ_PEK_LONG,
> -	AXP20X_IRQ_N_OE_PWR_ON,
> -	AXP20X_IRQ_N_OE_PWR_OFF,
> -	AXP20X_IRQ_VBUS_VALID,
> -	AXP20X_IRQ_VBUS_NOT_VALID,
> -	AXP20X_IRQ_VBUS_SESS_VALID,
> -	AXP20X_IRQ_VBUS_SESS_END,
> -	AXP20X_IRQ_LOW_PWR_LVL1,
> -	AXP20X_IRQ_LOW_PWR_LVL2,
> -	AXP20X_IRQ_TIMER,
> -	AXP20X_IRQ_PEK_RIS_EDGE,
> -	AXP20X_IRQ_PEK_FAL_EDGE,
> -	AXP20X_IRQ_GPIO3_INPUT,
> -	AXP20X_IRQ_GPIO2_INPUT,
> -	AXP20X_IRQ_GPIO1_INPUT,
> -	AXP20X_IRQ_GPIO0_INPUT,
> -};
> -
> -struct axp20x_dev {
> -	struct device			*dev;
> -	struct i2c_client		*i2c_client;
> -	struct regmap			*regmap;
> -	struct regmap_irq_chip_data	*regmap_irqc;
> -	long				variant;
> -};
> -
> -#endif /* __LINUX_MFD_AXP20X_H */
> diff --git a/include/linux/mfd/axp2xx.h b/include/linux/mfd/axp2xx.h
> new file mode 100644
> index 0000000..d0e31a2
> --- /dev/null
> +++ b/include/linux/mfd/axp2xx.h
> @@ -0,0 +1,180 @@
> +/*
> + * Functions and registers to access AXP20X power management chip.
> + *
> + * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
> + *
> + * 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 __LINUX_MFD_AXP20X_H
> +#define __LINUX_MFD_AXP20X_H
> +
> +enum {
> +	AXP202_ID = 0,
> +	AXP209_ID,
> +};
> +
> +#define AXP20X_DATACACHE(m)		(0x04 + (m))
> +
> +/* Power supply */
> +#define AXP20X_PWR_INPUT_STATUS		0x00
> +#define AXP20X_PWR_OP_MODE		0x01
> +#define AXP20X_USB_OTG_STATUS		0x02
> +#define AXP20X_PWR_OUT_CTRL		0x12
> +#define AXP20X_DCDC2_V_OUT		0x23
> +#define AXP20X_DCDC2_LDO3_V_SCAL	0x25
> +#define AXP20X_DCDC3_V_OUT		0x27
> +#define AXP20X_LDO24_V_OUT		0x28
> +#define AXP20X_LDO3_V_OUT		0x29
> +#define AXP20X_VBUS_IPSOUT_MGMT		0x30
> +#define AXP20X_V_OFF			0x31
> +#define AXP20X_OFF_CTRL			0x32
> +#define AXP20X_CHRG_CTRL1		0x33
> +#define AXP20X_CHRG_CTRL2		0x34
> +#define AXP20X_CHRG_BAK_CTRL		0x35
> +#define AXP20X_PEK_KEY			0x36
> +#define AXP20X_DCDC_FREQ		0x37
> +#define AXP20X_V_LTF_CHRG		0x38
> +#define AXP20X_V_HTF_CHRG		0x39
> +#define AXP20X_APS_WARN_L1		0x3a
> +#define AXP20X_APS_WARN_L2		0x3b
> +#define AXP20X_V_LTF_DISCHRG		0x3c
> +#define AXP20X_V_HTF_DISCHRG		0x3d
> +
> +/* Interrupt */
> +#define AXP20X_IRQ1_EN			0x40
> +#define AXP20X_IRQ2_EN			0x41
> +#define AXP20X_IRQ3_EN			0x42
> +#define AXP20X_IRQ4_EN			0x43
> +#define AXP20X_IRQ5_EN			0x44
> +#define AXP20X_IRQ1_STATE		0x48
> +#define AXP20X_IRQ2_STATE		0x49
> +#define AXP20X_IRQ3_STATE		0x4a
> +#define AXP20X_IRQ4_STATE		0x4b
> +#define AXP20X_IRQ5_STATE		0x4c
> +
> +/* ADC */
> +#define AXP20X_ACIN_V_ADC_H		0x56
> +#define AXP20X_ACIN_V_ADC_L		0x57
> +#define AXP20X_ACIN_I_ADC_H		0x58
> +#define AXP20X_ACIN_I_ADC_L		0x59
> +#define AXP20X_VBUS_V_ADC_H		0x5a
> +#define AXP20X_VBUS_V_ADC_L		0x5b
> +#define AXP20X_VBUS_I_ADC_H		0x5c
> +#define AXP20X_VBUS_I_ADC_L		0x5d
> +#define AXP20X_TEMP_ADC_H		0x5e
> +#define AXP20X_TEMP_ADC_L		0x5f
> +#define AXP20X_TS_IN_H			0x62
> +#define AXP20X_TS_IN_L			0x63
> +#define AXP20X_GPIO0_V_ADC_H		0x64
> +#define AXP20X_GPIO0_V_ADC_L		0x65
> +#define AXP20X_GPIO1_V_ADC_H		0x66
> +#define AXP20X_GPIO1_V_ADC_L		0x67
> +#define AXP20X_PWR_BATT_H		0x70
> +#define AXP20X_PWR_BATT_M		0x71
> +#define AXP20X_PWR_BATT_L		0x72
> +#define AXP20X_BATT_V_H			0x78
> +#define AXP20X_BATT_V_L			0x79
> +#define AXP20X_BATT_CHRG_I_H		0x7a
> +#define AXP20X_BATT_CHRG_I_L		0x7b
> +#define AXP20X_BATT_DISCHRG_I_H		0x7c
> +#define AXP20X_BATT_DISCHRG_I_L		0x7d
> +#define AXP20X_IPSOUT_V_HIGH_H		0x7e
> +#define AXP20X_IPSOUT_V_HIGH_L		0x7f
> +
> +/* Power supply */
> +#define AXP20X_DCDC_MODE		0x80
> +#define AXP20X_ADC_EN1			0x82
> +#define AXP20X_ADC_EN2			0x83
> +#define AXP20X_ADC_RATE			0x84
> +#define AXP20X_GPIO10_IN_RANGE		0x85
> +#define AXP20X_GPIO1_ADC_IRQ_RIS	0x86
> +#define AXP20X_GPIO1_ADC_IRQ_FAL	0x87
> +#define AXP20X_TIMER_CTRL		0x8a
> +#define AXP20X_VBUS_MON			0x8b
> +#define AXP20X_OVER_TMP			0x8f
> +
> +/* GPIO */
> +#define AXP20X_GPIO0_CTRL		0x90
> +#define AXP20X_LDO5_V_OUT		0x91
> +#define AXP20X_GPIO1_CTRL		0x92
> +#define AXP20X_GPIO2_CTRL		0x93
> +#define AXP20X_GPIO20_SS		0x94
> +#define AXP20X_GPIO3_CTRL		0x95
> +
> +/* Battery */
> +#define AXP20X_CHRG_CC_31_24		0xb0
> +#define AXP20X_CHRG_CC_23_16		0xb1
> +#define AXP20X_CHRG_CC_15_8		0xb2
> +#define AXP20X_CHRG_CC_7_0		0xb3
> +#define AXP20X_DISCHRG_CC_31_24		0xb4
> +#define AXP20X_DISCHRG_CC_23_16		0xb5
> +#define AXP20X_DISCHRG_CC_15_8		0xb6
> +#define AXP20X_DISCHRG_CC_7_0		0xb7
> +#define AXP20X_CC_CTRL			0xb8
> +#define AXP20X_FG_RES			0xb9
> +
> +/* Regulators IDs */
> +enum {
> +	AXP20X_LDO1 = 0,
> +	AXP20X_LDO2,
> +	AXP20X_LDO3,
> +	AXP20X_LDO4,
> +	AXP20X_LDO5,
> +	AXP20X_DCDC2,
> +	AXP20X_DCDC3,
> +	AXP20X_REG_ID_MAX,
> +};
> +
> +/* IRQs */
> +enum {
> +	AXP20X_IRQ_ACIN_OVER_V = 1,
> +	AXP20X_IRQ_ACIN_PLUGIN,
> +	AXP20X_IRQ_ACIN_REMOVAL,
> +	AXP20X_IRQ_VBUS_OVER_V,
> +	AXP20X_IRQ_VBUS_PLUGIN,
> +	AXP20X_IRQ_VBUS_REMOVAL,
> +	AXP20X_IRQ_VBUS_V_LOW,
> +	AXP20X_IRQ_BATT_PLUGIN,
> +	AXP20X_IRQ_BATT_REMOVAL,
> +	AXP20X_IRQ_BATT_ENT_ACT_MODE,
> +	AXP20X_IRQ_BATT_EXIT_ACT_MODE,
> +	AXP20X_IRQ_CHARG,
> +	AXP20X_IRQ_CHARG_DONE,
> +	AXP20X_IRQ_BATT_TEMP_HIGH,
> +	AXP20X_IRQ_BATT_TEMP_LOW,
> +	AXP20X_IRQ_DIE_TEMP_HIGH,
> +	AXP20X_IRQ_CHARG_I_LOW,
> +	AXP20X_IRQ_DCDC1_V_LONG,
> +	AXP20X_IRQ_DCDC2_V_LONG,
> +	AXP20X_IRQ_DCDC3_V_LONG,
> +	AXP20X_IRQ_PEK_SHORT = 22,
> +	AXP20X_IRQ_PEK_LONG,
> +	AXP20X_IRQ_N_OE_PWR_ON,
> +	AXP20X_IRQ_N_OE_PWR_OFF,
> +	AXP20X_IRQ_VBUS_VALID,
> +	AXP20X_IRQ_VBUS_NOT_VALID,
> +	AXP20X_IRQ_VBUS_SESS_VALID,
> +	AXP20X_IRQ_VBUS_SESS_END,
> +	AXP20X_IRQ_LOW_PWR_LVL1,
> +	AXP20X_IRQ_LOW_PWR_LVL2,
> +	AXP20X_IRQ_TIMER,
> +	AXP20X_IRQ_PEK_RIS_EDGE,
> +	AXP20X_IRQ_PEK_FAL_EDGE,
> +	AXP20X_IRQ_GPIO3_INPUT,
> +	AXP20X_IRQ_GPIO2_INPUT,
> +	AXP20X_IRQ_GPIO1_INPUT,
> +	AXP20X_IRQ_GPIO0_INPUT,
> +};
> +
> +struct axp20x_dev {
> +	struct device			*dev;
> +	struct i2c_client		*i2c_client;
> +	struct regmap			*regmap;
> +	struct regmap_irq_chip_data	*regmap_irqc;
> +	long				variant;
> +};
> +
> +#endif /* __LINUX_MFD_AXP20X_H */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header
  2014-09-08 22:24 ` [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header Jacob Pan
@ 2014-09-09 11:25   ` Mark Brown
  2014-09-11 22:26     ` Jacob Pan
  0 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2014-09-09 11:25 UTC (permalink / raw)
  To: Jacob Pan
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

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

On Mon, Sep 08, 2014 at 03:24:05PM -0700, Jacob Pan wrote:
> AXP20x driver has been extended to support axp288 variant. Header file
> and common data structures has also been renamed to suit the new
> scope of devices supported.
> 
> This patch makes use of the renamed header and structure.

> -#include <linux/mfd/axp20x.h>
> +#include <linux/mfd/axp2xx.h>

Acked-by: Mark Brown <broonie@kernel.org>

but is it really worth the effort of renaming everything?  That's going
to cause problems for things like the stable workflow.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic
  2014-09-09  7:37   ` Maxime Ripard
@ 2014-09-09 12:45     ` Jacob Pan
  2014-09-09 13:37       ` Maxime Ripard
  0 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-09 12:45 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood, Mark Brown,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

On Tue, 9 Sep 2014 09:37:47 +0200
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Hi Jacob,
> 
> I think it would have been nice to have CC'd Carlo Caione, the
> original writer of the driver on this.
> 
yes, i realized that after sending them out, so i sent him an email
instead. run get_maintainers.pl gave me a long list but missing carlo.
will be on the next rev.
> On Mon, Sep 08, 2014 at 03:24:04PM -0700, Jacob Pan wrote:
> > XPower AXP288 is a customized PMIC for Intel Baytrail-CR platforms.
> > Similar to AXP202/209, AXP288 comes with USB charger, more LDO and
> > BUCK channels, and AD converter. It also provides extended status
> > and interrupt reporting capabilities than the devices supported in
> > axp20x.c.
> > 
> > In addition to feature extension, this patch also adds ACPI binding
> > for enumeration and hooks for ACPI custom operational region
> > handlers.
> > 
> > Files and common data structures have been renamed from axp20x to
> > axp2xx in order to suit the extended scope of devices.
> > 
> > This consolidated driver should support more Xpower PMICs in both
> > device tree and ACPI based platforms.
> > 
> > Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> > ---
> >  drivers/mfd/axp2xx.c       | 424
> > +++++++++++++++++++++++++++++++++++----------
> > include/linux/mfd/axp2xx.h |  57 +++++- 2 files changed, 389
> > insertions(+), 92 deletions(-)
> > 
> > diff --git a/drivers/mfd/axp2xx.c b/drivers/mfd/axp2xx.c
> > index c534443..cf7ed16 100644
> > --- a/drivers/mfd/axp2xx.c
> > +++ b/drivers/mfd/axp2xx.c
> > @@ -1,10 +1,14 @@
> >  /*
> > - * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
> > + * axp2xx.c - MFD core driver for the X-Powers AXP202, AXP209, and
> > AXP288
> 
> Could you do the s/axp20x/axp2xx/ in the first patch? It would make
> more sense to have it there, and reduce the "noise" in this patch.
> 
> >   *
> >   * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK
> > DC-DC
> >   * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current
> > and temperature
> >   * as well as 4 configurable GPIOs.
> >   *
> > + * AXP288 is a customized PMIC for Intel Baytrail CR platform.
> > Similar to AXP20x
> > + * it comes with USB charger, more LDO, BUCK channels, and status
> > reporting
> > + * capabilities.
> > + *
> 
> Also, I'm not very convinced that maintaining the list of the
> supported AXP chips is very future proof. We have at least 3 other
> variants that we know of to support (AXP221, AXP223 and
> AXP806/809). This would end up in a huge list :)
> 
agreed. perhaps just a generic description of functionalities here.
> >   * Author: Carlo Caione <carlo@caione.org>
> >   *
> >   * This program is free software; you can redistribute it and/or
> > modify @@ -25,9 +29,14 @@
> >  #include <linux/mfd/core.h>
> >  #include <linux/of_device.h>
> >  #include <linux/of_irq.h>
> > +#include <linux/acpi.h>
> >  
> >  #define AXP20X_OFF	0x80
> >  
> > +static struct mfd_cell *axp2xx_cells;
> > +static int axp2xx_nr_cells;
> > +static struct regmap_config *regmap_cfg;
> > +
> >  static const struct regmap_range axp20x_writeable_ranges[] = {
> >  	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
> >  	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
> > @@ -47,6 +56,25 @@ static const struct regmap_access_table
> > axp20x_volatile_table = { .n_yes_ranges	=
> > ARRAY_SIZE(axp20x_volatile_ranges), };
> >  
> > +static const struct regmap_range axp288_writeable_ranges[] = {
> > +	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
> > +	regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
> > +};
> > +
> > +static const struct regmap_range axp288_volatile_ranges[] = {
> > +	regmap_reg_range(AXP20X_IRQ1_EN,  AXP20X_IPSOUT_V_HIGH_L),
> > +};
> > +
> > +static const struct regmap_access_table axp288_writeable_table = {
> > +	.yes_ranges	= axp288_writeable_ranges,
> > +	.n_yes_ranges	= ARRAY_SIZE(axp288_writeable_ranges),
> > +};
> > +
> > +static const struct regmap_access_table axp288_volatile_table = {
> > +	.yes_ranges	= axp288_volatile_ranges,
> > +	.n_yes_ranges	= ARRAY_SIZE(axp288_volatile_ranges),
> > +};
> > +
> >  static struct resource axp20x_pek_resources[] = {
> >  	{
> >  		.name	= "PEK_DBR",
> > @@ -61,7 +89,40 @@ static struct resource axp20x_pek_resources[] = {
> >  	},
> >  };
> >  
> > -static const struct regmap_config axp20x_regmap_config = {
> > +static struct resource axp288_battery_resources[] = {
> > +	{
> > +		.start = AXP288_IRQ_QWBTU,
> > +		.end   = AXP288_IRQ_QWBTU,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_WBTU,
> > +		.end   = AXP288_IRQ_WBTU,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_QWBTO,
> > +		.end   = AXP288_IRQ_QWBTO,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_WBTO,
> > +		.end   = AXP288_IRQ_WBTO,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_WL2,
> > +		.end   = AXP288_IRQ_WL2,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_WL1,
> > +		.end   = AXP288_IRQ_WL1,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct regmap_config axp20x_regmap_config = {
> >  	.reg_bits	= 8,
> >  	.val_bits	= 8,
> >  	.wr_table	= &axp20x_writeable_table,
> > @@ -70,47 +131,96 @@ static const struct regmap_config
> > axp20x_regmap_config = { .cache_type	= REGCACHE_RBTREE,
> >  };
> >  
> > -#define AXP20X_IRQ(_irq, _off, _mask) \
> > -	[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask =
> > BIT(_mask) } +static struct regmap_config axp288_regmap_config = {
> > +	.reg_bits	= 8,
> > +	.val_bits	= 8,
> > +	.wr_table	= &axp288_writeable_table,
> > +	.volatile_table	= &axp288_volatile_table,
> > +	.max_register	= AXP288_FG_TUNE5,
> > +	.cache_type	= REGCACHE_RBTREE,
> > +};
> > +
> > +#define INIT_REGMAP_IRQ(_variant, _irq, _off,
> > _mask)			\
> > +	[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask =
> > BIT(_mask) } 
> >  static const struct regmap_irq axp20x_regmap_irqs[] = {
> > -	AXP20X_IRQ(ACIN_OVER_V,		0, 7),
> > -	AXP20X_IRQ(ACIN_PLUGIN,		0, 6),
> > -	AXP20X_IRQ(ACIN_REMOVAL,	0, 5),
> > -	AXP20X_IRQ(VBUS_OVER_V,		0, 4),
> > -	AXP20X_IRQ(VBUS_PLUGIN,		0, 3),
> > -	AXP20X_IRQ(VBUS_REMOVAL,	0, 2),
> > -	AXP20X_IRQ(VBUS_V_LOW,		0, 1),
> > -	AXP20X_IRQ(BATT_PLUGIN,		1, 7),
> > -	AXP20X_IRQ(BATT_REMOVAL,	1, 6),
> > -	AXP20X_IRQ(BATT_ENT_ACT_MODE,	1, 5),
> > -	AXP20X_IRQ(BATT_EXIT_ACT_MODE,	1, 4),
> > -	AXP20X_IRQ(CHARG,		1, 3),
> > -	AXP20X_IRQ(CHARG_DONE,		1, 2),
> > -	AXP20X_IRQ(BATT_TEMP_HIGH,	1, 1),
> > -	AXP20X_IRQ(BATT_TEMP_LOW,	1, 0),
> > -	AXP20X_IRQ(DIE_TEMP_HIGH,	2, 7),
> > -	AXP20X_IRQ(CHARG_I_LOW,		2, 6),
> > -	AXP20X_IRQ(DCDC1_V_LONG,	2, 5),
> > -	AXP20X_IRQ(DCDC2_V_LONG,	2, 4),
> > -	AXP20X_IRQ(DCDC3_V_LONG,	2, 3),
> > -	AXP20X_IRQ(PEK_SHORT,		2, 1),
> > -	AXP20X_IRQ(PEK_LONG,		2, 0),
> > -	AXP20X_IRQ(N_OE_PWR_ON,		3, 7),
> > -	AXP20X_IRQ(N_OE_PWR_OFF,	3, 6),
> > -	AXP20X_IRQ(VBUS_VALID,		3, 5),
> > -	AXP20X_IRQ(VBUS_NOT_VALID,	3, 4),
> > -	AXP20X_IRQ(VBUS_SESS_VALID,	3, 3),
> > -	AXP20X_IRQ(VBUS_SESS_END,	3, 2),
> > -	AXP20X_IRQ(LOW_PWR_LVL1,	3, 1),
> > -	AXP20X_IRQ(LOW_PWR_LVL2,	3, 0),
> > -	AXP20X_IRQ(TIMER,		4, 7),
> > -	AXP20X_IRQ(PEK_RIS_EDGE,	4, 6),
> > -	AXP20X_IRQ(PEK_FAL_EDGE,	4, 5),
> > -	AXP20X_IRQ(GPIO3_INPUT,		4, 3),
> > -	AXP20X_IRQ(GPIO2_INPUT,		4, 2),
> > -	AXP20X_IRQ(GPIO1_INPUT,		4, 1),
> > -	AXP20X_IRQ(GPIO0_INPUT,		4, 0),
> > +	INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V,		0, 7),
> > +	INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN,		0, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL,	        0, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,		0, 4),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,		0, 3),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,	        0, 2),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW,		0, 1),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,		1, 7),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,	        1, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE,	1, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE,	1, 4),
> > +	INIT_REGMAP_IRQ(AXP20X, CHARG,		        1,
> > 3),
> > +	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,		1, 2),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH,	        1,
> > 1),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW,	        1,
> > 0),
> > +	INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH,	        2,
> > 7),
> > +	INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW,		2, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG,	        2, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG,	        2, 4),
> > +	INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG,	        2, 3),
> > +	INIT_REGMAP_IRQ(AXP20X, PEK_SHORT,		2, 1),
> > +	INIT_REGMAP_IRQ(AXP20X, PEK_LONG,		2, 0),
> > +	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON,		3, 7),
> > +	INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF,	        3, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_VALID,		3, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID,	        3,
> > 4),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID,	3, 3),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END,	        3,
> > 2),
> > +	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1,	        3, 1),
> > +	INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2,	        3, 0),
> > +	INIT_REGMAP_IRQ(AXP20X, TIMER,		        4,
> > 7),
> > +	INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE,	        4, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE,	        4, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT,		4, 3),
> > +	INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT,		4, 2),
> > +	INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT,		4, 1),
> > +	INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT,		4, 0),
> > +};
> > +
> > +/* some IRQs are compatible with axp20x models */
> > +static const struct regmap_irq axp288_regmap_irqs[] = {
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,           0, 2),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,            0, 3),
> > +	INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,            0, 4),
> > +
> > +	INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,             1, 2),
> > +	INIT_REGMAP_IRQ(AXP20X, CHARG,                  1, 3),
> > +	INIT_REGMAP_IRQ(AXP288, SAFE_QUIT,              1, 4),
> > +	INIT_REGMAP_IRQ(AXP288, SAFE_ENTER,             1, 5),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,           1, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,            1, 7),
> > +
> > +	INIT_REGMAP_IRQ(AXP288, QWBTU,                  2, 0),
> > +	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 1),
> > +	INIT_REGMAP_IRQ(AXP288, QWBTO,                  2, 2),
> > +	INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 3),
> > +	INIT_REGMAP_IRQ(AXP288, QCBTU,                  2, 4),
> > +	INIT_REGMAP_IRQ(AXP288, CBTU,                   2, 5),
> > +	INIT_REGMAP_IRQ(AXP288, QCBTO,                  2, 6),
> > +	INIT_REGMAP_IRQ(AXP288, CBTO,                   2, 7),
> > +
> > +	INIT_REGMAP_IRQ(AXP288, WL2,                    3, 0),
> > +	INIT_REGMAP_IRQ(AXP288, WL1,                    3, 1),
> > +	INIT_REGMAP_IRQ(AXP288, GPADC,                  3, 2),
> > +	INIT_REGMAP_IRQ(AXP288, OT,                     3, 7),
> > +
> > +	INIT_REGMAP_IRQ(AXP288, GPIO0,                  4, 0),
> > +	INIT_REGMAP_IRQ(AXP288, GPIO1,                  4, 1),
> > +	INIT_REGMAP_IRQ(AXP288, POKO,                   4, 2),
> > +	INIT_REGMAP_IRQ(AXP288, POKL,                   4, 3),
> > +	INIT_REGMAP_IRQ(AXP288, POKS,                   4, 4),
> > +	INIT_REGMAP_IRQ(AXP288, POKN,                   4, 5),
> > +	INIT_REGMAP_IRQ(AXP288, POKP,                   4, 6),
> > +	INIT_REGMAP_IRQ(AXP20X, TIMER,                  4, 7),
> > +
> > +	INIT_REGMAP_IRQ(AXP288, MV_CHNG,                5, 0),
> > +	INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG,            5, 1),
> >  };
> >  
> >  static const struct of_device_id axp20x_of_match[] = {
> > @@ -123,19 +233,26 @@ MODULE_DEVICE_TABLE(of, axp20x_of_match);
> >  /*
> >   * This is useless for OF-enabled devices, but it is needed by I2C
> > subsystem */
> > -static const struct i2c_device_id axp20x_i2c_id[] = {
> > +static const struct i2c_device_id axp2xx_i2c_id[] = {
> >  	{ },
> >  };
> > -MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
> > +MODULE_DEVICE_TABLE(i2c, axp2xx_i2c_id);
> >  
> > -static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
> > -	.name			= "axp20x_irq_chip",
> > +static struct acpi_device_id axp2xx_acpi_match[] = {
> > +	{
> > +		.id = "INT33F4",
> > +		.driver_data = (kernel_ulong_t)AXP288_ID,
> > +	},
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(acpi, axp2xx_acpi_match);
> > +
> > +/* common irq chip attributes only */
> > +static struct regmap_irq_chip axp2xx_regmap_irq_chip = {
> > +	.name			= "axp2xx_irq_chip",
> >  	.status_base		= AXP20X_IRQ1_STATE,
> >  	.ack_base		= AXP20X_IRQ1_STATE,
> >  	.mask_base		= AXP20X_IRQ1_EN,
> > -	.num_regs		= 5,
> > -	.irqs			= axp20x_regmap_irqs,
> > -	.num_irqs		= ARRAY_SIZE(axp20x_regmap_irqs),
> >  	.mask_invert		= true,
> >  	.init_ack_masked	= true,
> >  };
> > @@ -161,98 +278,223 @@ static struct mfd_cell axp20x_cells[] = {
> >  	},
> >  };
> >  
> > -static struct axp20x_dev *axp20x_pm_power_off;
> > -static void axp20x_power_off(void)
> > +static struct resource axp288_adc_resources[] = {
> > +	{
> > +		.name	= "GPADC",
> > +		.start = AXP288_IRQ_GPADC,
> > +		.end   = AXP288_IRQ_GPADC,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct resource axp288_charger_resources[] = {
> > +	{
> > +		.start = AXP288_IRQ_OV,
> > +		.end   = AXP288_IRQ_OV,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_DONE,
> > +		.end   = AXP288_IRQ_DONE,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_CHARGING,
> > +		.end   = AXP288_IRQ_CHARGING,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_SAFE_QUIT,
> > +		.end   = AXP288_IRQ_SAFE_QUIT,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_SAFE_ENTER,
> > +		.end   = AXP288_IRQ_SAFE_ENTER,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_QCBTU,
> > +		.end   = AXP288_IRQ_QCBTU,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_CBTU,
> > +		.end   = AXP288_IRQ_CBTU,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_QCBTO,
> > +		.end   = AXP288_IRQ_QCBTO,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.start = AXP288_IRQ_CBTO,
> > +		.end   = AXP288_IRQ_CBTO,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct mfd_cell axp288_cells[] = {
> > +	{
> > +		.name = "axp288_adc",
> > +		.num_resources = ARRAY_SIZE(axp288_adc_resources),
> > +		.resources = axp288_adc_resources,
> > +	},
> > +	{
> > +		.name = "axp288_charger",
> > +		.num_resources =
> > ARRAY_SIZE(axp288_charger_resources),
> > +		.resources = axp288_charger_resources,
> > +	},
> > +	{
> > +		.name = "axp288_battery",
> > +		.num_resources =
> > ARRAY_SIZE(axp288_battery_resources),
> > +		.resources = axp288_battery_resources,
> > +	},
> > +	{
> > +		.name = "axp288_acpi_opregion",
> > +	},
> > +};
> > +
> > +static struct axp2xx_dev *axp2xx_pm_power_off;
> > +static void axp2xx_power_off(void)
> >  {
> > -	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
> > +	if (axp2xx_pm_power_off->variant == AXP288_ID)
> > +		return;
> > +	regmap_write(axp2xx_pm_power_off->regmap, AXP20X_OFF_CTRL,
> >  		     AXP20X_OFF);
> >  }
> >  
> > -static int axp20x_i2c_probe(struct i2c_client *i2c,
> > -			 const struct i2c_device_id *id)
> > +static int axp2xx_match_device(struct axp2xx_dev *axp2xx, struct
> > device *dev) {
> > -	struct axp20x_dev *axp20x;
> > +	const struct acpi_device_id *acpi_id;
> >  	const struct of_device_id *of_id;
> > -	int ret;
> >  
> > -	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x),
> > GFP_KERNEL);
> > -	if (!axp20x)
> > -		return -ENOMEM;
> > +	of_id = of_match_device(axp2xx_of_match, dev);
> > +	if (of_id) {
> > +		axp2xx->variant = (long) of_id->data;
> > +		goto found_match;
> > +	}
> >  
> > -	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> > -	if (!of_id) {
> > -		dev_err(&i2c->dev, "Unable to setup AXP20X
> > data\n");
> > +	acpi_id = acpi_match_device(dev->driver->acpi_match_table,
> > dev);
> > +	if (!acpi_id || !acpi_id->driver_data) {
> > +		dev_err(dev, "Unable to setup AXP2XX ACPI data\n");
> >  		return -ENODEV;
> >  	}
> > -	axp20x->variant = (long) of_id->data;
> > +	axp2xx->variant = (long) acpi_id->driver_data;
> 
> Shouldn't that be in the if statement above? I guess acpi_id will be
> null on a DT-based system.
> 
I am not sure what you mean. if acpi_id == NULL, then it will return
-ENODEV since of_match_device() already found no match. If acpi_id !=
NULL, then id must contain variant info.
> > +
> > +found_match:
> > +	switch (axp2xx->variant) {
> > +	case AXP202_ID:
> > +	case AXP209_ID:
> > +		dev_dbg(dev, "AXP2xx variant AXP202/209 found\n");
> > +		axp2xx_nr_cells = ARRAY_SIZE(axp20x_cells);
> > +		axp2xx_cells = axp20x_cells;
> > +		regmap_cfg = &axp20x_regmap_config;
> > +		axp2xx_regmap_irq_chip.num_regs	= 5;
> > +		axp2xx_regmap_irq_chip.irqs = axp20x_regmap_irqs;
> > +		axp2xx_regmap_irq_chip.num_irqs	=
> > +			ARRAY_SIZE(axp20x_regmap_irqs);
> > +		break;
> > +	case AXP288_ID:
> > +		dev_dbg(dev, "AXP2xx variant AXP288 found\n");
> > +		axp2xx_cells = axp288_cells;
> > +		axp2xx_nr_cells = ARRAY_SIZE(axp288_cells);
> > +		axp2xx_regmap_irq_chip.irqs = axp288_regmap_irqs;
> > +		axp2xx_regmap_irq_chip.num_irqs	=
> > +			ARRAY_SIZE(axp288_regmap_irqs);
> > +		axp2xx_regmap_irq_chip.num_regs	= 6;
> > +		regmap_cfg = &axp288_regmap_config;
> > +		break;
> > +	default:
> > +		dev_err(dev, "unsupported AXP2XX ID %lu\n",
> > axp2xx->variant);
> > +		return -ENODEV;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int axp2xx_i2c_probe(struct i2c_client *i2c,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct axp2xx_dev *axp2xx;
> > +	int ret;
> >  
> > -	axp20x->i2c_client = i2c;
> > -	axp20x->dev = &i2c->dev;
> > -	dev_set_drvdata(axp20x->dev, axp20x);
> > +	axp2xx = devm_kzalloc(&i2c->dev, sizeof(*axp2xx),
> > GFP_KERNEL);
> > +	if (!axp2xx)
> > +		return -ENOMEM;
> > +
> > +	ret = axp2xx_match_device(axp2xx, &i2c->dev);
> > +	if (ret)
> > +		return ret;
> > +	axp2xx->i2c_client = i2c;
> > +	axp2xx->dev = &i2c->dev;
> > +	dev_set_drvdata(axp2xx->dev, axp2xx);
> >  
> > -	axp20x->regmap = devm_regmap_init_i2c(i2c,
> > &axp20x_regmap_config);
> > -	if (IS_ERR(axp20x->regmap)) {
> > -		ret = PTR_ERR(axp20x->regmap);
> > +	axp2xx->regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
> > +	if (IS_ERR(axp2xx->regmap)) {
> > +		ret = PTR_ERR(axp2xx->regmap);
> >  		dev_err(&i2c->dev, "regmap init failed: %d\n",
> > ret); return ret;
> >  	}
> >  
> > -	ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
> > +	ret = regmap_add_irq_chip(axp2xx->regmap, i2c->irq,
> >  				  IRQF_ONESHOT | IRQF_SHARED, -1,
> > -				  &axp20x_regmap_irq_chip,
> > -				  &axp20x->regmap_irqc);
> > +				  &axp2xx_regmap_irq_chip,
> > +				  &axp2xx->regmap_irqc);
> >  	if (ret) {
> >  		dev_err(&i2c->dev, "failed to add irq chip: %d\n",
> > ret); return ret;
> >  	}
> >  
> > -	ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
> > -			      ARRAY_SIZE(axp20x_cells), NULL, 0,
> > NULL);
> > +	ret = mfd_add_devices(axp2xx->dev, -1, axp2xx_cells,
> > +			axp2xx_nr_cells, NULL, 0, NULL);
> >  
> >  	if (ret) {
> >  		dev_err(&i2c->dev, "failed to add MFD devices:
> > %d\n", ret);
> > -		regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
> > +		regmap_del_irq_chip(i2c->irq, axp2xx->regmap_irqc);
> >  		return ret;
> >  	}
> >  
> >  	if (!pm_power_off) {
> > -		axp20x_pm_power_off = axp20x;
> > -		pm_power_off = axp20x_power_off;
> > +		axp2xx_pm_power_off = axp2xx;
> > +		pm_power_off = axp2xx_power_off;
> >  	}
> >  
> > -	dev_info(&i2c->dev, "AXP20X driver loaded\n");
> > +	dev_info(&i2c->dev, "AXP2XX driver loaded\n");
> >  
> >  	return 0;
> >  }
> >  
> > -static int axp20x_i2c_remove(struct i2c_client *i2c)
> > +static int axp2xx_i2c_remove(struct i2c_client *i2c)
> >  {
> > -	struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
> > +	struct axp2xx_dev *axp2xx = i2c_get_clientdata(i2c);
> >  
> > -	if (axp20x == axp20x_pm_power_off) {
> > -		axp20x_pm_power_off = NULL;
> > +	if (axp2xx == axp2xx_pm_power_off) {
> > +		axp2xx_pm_power_off = NULL;
> >  		pm_power_off = NULL;
> >  	}
> >  
> > -	mfd_remove_devices(axp20x->dev);
> > -	regmap_del_irq_chip(axp20x->i2c_client->irq,
> > axp20x->regmap_irqc);
> > +	mfd_remove_devices(axp2xx->dev);
> > +	regmap_del_irq_chip(axp2xx->i2c_client->irq,
> > axp2xx->regmap_irqc); 
> >  	return 0;
> >  }
> >  
> > -static struct i2c_driver axp20x_i2c_driver = {
> > +static struct i2c_driver axp2xx_i2c_driver = {
> >  	.driver = {
> > -		.name	= "axp20x",
> > +		.name	= "axp2xx",
> >  		.owner	= THIS_MODULE,
> > -		.of_match_table	=
> > of_match_ptr(axp20x_of_match),
> > +		.of_match_table	=
> > of_match_ptr(axp2xx_of_match),
> > +		.acpi_match_table = ACPI_PTR(axp2xx_acpi_match),
> >  	},
> > -	.probe		= axp20x_i2c_probe,
> > -	.remove		= axp20x_i2c_remove,
> > -	.id_table	= axp20x_i2c_id,
> > +	.probe		= axp2xx_i2c_probe,
> > +	.remove		= axp2xx_i2c_remove,
> > +	.id_table	= axp2xx_i2c_id,
> >  };
> >  
> > -module_i2c_driver(axp20x_i2c_driver);
> > +module_i2c_driver(axp2xx_i2c_driver);
> >  
> > -MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
> > +MODULE_DESCRIPTION("PMIC MFD core driver for AXP2XX");
> >  MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
> >  MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/axp2xx.h b/include/linux/mfd/axp2xx.h
> > index d0e31a2..672f048 100644
> > --- a/include/linux/mfd/axp2xx.h
> > +++ b/include/linux/mfd/axp2xx.h
> > @@ -14,6 +14,8 @@
> >  enum {
> >  	AXP202_ID = 0,
> >  	AXP209_ID,
> > +	AXP288_ID,
> > +	NR_AXP288_VARIANTS,
> 
> Can't that be a more generic name? Something like NR_AXP2XX instead?
> 
> Also, could you put me in CC in the later iterations of the patches?
> 
Yes, agreed.

Thanks for the review.
> Thanks!
> Maxime
> 

[Jacob Pan]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic
  2014-09-09 12:45     ` Jacob Pan
@ 2014-09-09 13:37       ` Maxime Ripard
  2014-09-11 22:23         ` Jacob Pan
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Ripard @ 2014-09-09 13:37 UTC (permalink / raw)
  To: Jacob Pan
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood, Mark Brown,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

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

On Tue, Sep 09, 2014 at 05:45:17AM -0700, Jacob Pan wrote:
> > > -static int axp20x_i2c_probe(struct i2c_client *i2c,
> > > -			 const struct i2c_device_id *id)
> > > +static int axp2xx_match_device(struct axp2xx_dev *axp2xx, struct
> > > device *dev) {
> > > -	struct axp20x_dev *axp20x;
> > > +	const struct acpi_device_id *acpi_id;
> > >  	const struct of_device_id *of_id;
> > > -	int ret;
> > >  
> > > -	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x),
> > > GFP_KERNEL);
> > > -	if (!axp20x)
> > > -		return -ENOMEM;
> > > +	of_id = of_match_device(axp2xx_of_match, dev);
> > > +	if (of_id) {
> > > +		axp2xx->variant = (long) of_id->data;
> > > +		goto found_match;
> > > +	}
> > >  
> > > -	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> > > -	if (!of_id) {
> > > -		dev_err(&i2c->dev, "Unable to setup AXP20X
> > > data\n");
> > > +	acpi_id = acpi_match_device(dev->driver->acpi_match_table,
> > > dev);
> > > +	if (!acpi_id || !acpi_id->driver_data) {
> > > +		dev_err(dev, "Unable to setup AXP2XX ACPI data\n");
> > >  		return -ENODEV;
> > >  	}
> > > -	axp20x->variant = (long) of_id->data;
> > > +	axp2xx->variant = (long) acpi_id->driver_data;
> > 
> > Shouldn't that be in the if statement above? I guess acpi_id will be
> > null on a DT-based system.
> > 
> I am not sure what you mean. if acpi_id == NULL, then it will return
> -ENODEV since of_match_device() already found no match. If acpi_id !=
> NULL, then id must contain variant info.

Hmm, never mind. I read it backward and thought you were still in this
code path. I guess I need more coffee.

That goto isn't very intuitive though.

Maybe something like

if (of_id) {
   /* DT case */
} else if (acpi_id) {
  /* ACPI case */
} else {
  return;
}

would be better?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc
  2014-09-08 22:24 ` [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc Jacob Pan
@ 2014-09-10  4:19   ` Pallala, Ramakrishna
  0 siblings, 0 replies; 14+ messages in thread
From: Pallala, Ramakrishna @ 2014-09-10  4:19 UTC (permalink / raw)
  To: Jacob Pan, IIO, LKML, DEVICE TREE, Lee Jones
  Cc: Srinivas Pandruvada, Lu, Aaron, Alan Cox, Jean Delvare,
	Samuel Ortiz, Liam Girdwood, Mark Brown, Grant Likely,
	Greg Kroah-Hartman, Rob Herring, Lars-Peter Clausen,
	Hartmut Knaack, Fugang Duan, Arnd Bergmann, Zubair Lutfullah,
	Sebastian Reichel, Johannes Thumshirn, Philippe Reynes,
	Angelo Compagnucci, Doug Anderson

Hi Jacob,

> +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) static int 
> +axp288_gpadc_suspend(struct device *dev) {
> +	int ret;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct gpadc_info *info = iio_priv(indio_dev);
> +
> +	mutex_lock(&indio_dev->mlock);
> +	ret = axp288_gpadc_enable(info->regmap, false);
> +	mutex_unlock(&indio_dev->mlock);
> +
> +	return ret;
> +}

AXP288 has integrated fuel gauge which relies on VBATT and IBATT ADC measurements. If we disable the ADC then Fuel Gauge will get stuck.
So for the proper functioning of this integrated fuel gauging ADC measurements should always be ON.

Thanks,
Ram

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic
  2014-09-09 13:37       ` Maxime Ripard
@ 2014-09-11 22:23         ` Jacob Pan
  0 siblings, 0 replies; 14+ messages in thread
From: Jacob Pan @ 2014-09-11 22:23 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood, Mark Brown,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

On Tue, 9 Sep 2014 15:37:04 +0200
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> On Tue, Sep 09, 2014 at 05:45:17AM -0700, Jacob Pan wrote:
> > > > -static int axp20x_i2c_probe(struct i2c_client *i2c,
> > > > -			 const struct i2c_device_id *id)
> > > > +static int axp2xx_match_device(struct axp2xx_dev *axp2xx,
> > > > struct device *dev) {
> > > > -	struct axp20x_dev *axp20x;
> > > > +	const struct acpi_device_id *acpi_id;
> > > >  	const struct of_device_id *of_id;
> > > > -	int ret;
> > > >  
> > > > -	axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x),
> > > > GFP_KERNEL);
> > > > -	if (!axp20x)
> > > > -		return -ENOMEM;
> > > > +	of_id = of_match_device(axp2xx_of_match, dev);
> > > > +	if (of_id) {
> > > > +		axp2xx->variant = (long) of_id->data;
> > > > +		goto found_match;
> > > > +	}
> > > >  
> > > > -	of_id = of_match_device(axp20x_of_match, &i2c->dev);
> > > > -	if (!of_id) {
> > > > -		dev_err(&i2c->dev, "Unable to setup AXP20X
> > > > data\n");
> > > > +	acpi_id =
> > > > acpi_match_device(dev->driver->acpi_match_table, dev);
> > > > +	if (!acpi_id || !acpi_id->driver_data) {
> > > > +		dev_err(dev, "Unable to setup AXP2XX ACPI
> > > > data\n"); return -ENODEV;
> > > >  	}
> > > > -	axp20x->variant = (long) of_id->data;
> > > > +	axp2xx->variant = (long) acpi_id->driver_data;
> > > 
> > > Shouldn't that be in the if statement above? I guess acpi_id will
> > > be null on a DT-based system.
> > > 
> > I am not sure what you mean. if acpi_id == NULL, then it will return
> > -ENODEV since of_match_device() already found no match. If
> > acpi_id != NULL, then id must contain variant info.
> 
> Hmm, never mind. I read it backward and thought you were still in this
> code path. I guess I need more coffee.
> 
> That goto isn't very intuitive though.
> 
> Maybe something like
> 
> if (of_id) {
>    /* DT case */
> } else if (acpi_id) {
>   /* ACPI case */
> } else {
>   return;
> }
> 
> would be better?
> 
yes, will be in v3.

thanks.
> Maxime
> 

[Jacob Pan]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header
  2014-09-09 11:25   ` Mark Brown
@ 2014-09-11 22:26     ` Jacob Pan
  2014-09-12  7:39       ` Mark Brown
  0 siblings, 1 reply; 14+ messages in thread
From: Jacob Pan @ 2014-09-11 22:26 UTC (permalink / raw)
  To: Mark Brown
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

On Tue, 9 Sep 2014 12:25:16 +0100
Mark Brown <broonie@debian.org> wrote:

> On Mon, Sep 08, 2014 at 03:24:05PM -0700, Jacob Pan wrote:
> > AXP20x driver has been extended to support axp288 variant. Header
> > file and common data structures has also been renamed to suit the
> > new scope of devices supported.
> > 
> > This patch makes use of the renamed header and structure.
> 
> > -#include <linux/mfd/axp20x.h>
> > +#include <linux/mfd/axp2xx.h>
> 
> Acked-by: Mark Brown <broonie@kernel.org>
> 
> but is it really worth the effort of renaming everything?  That's
> going to cause problems for things like the stable workflow.

sorry for the late reply. IMHO, consistent and correct naming has
longer term benefit. how can i help to make the stable workflow easier?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header
  2014-09-11 22:26     ` Jacob Pan
@ 2014-09-12  7:39       ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2014-09-12  7:39 UTC (permalink / raw)
  To: Jacob Pan
  Cc: IIO, LKML, DEVICE TREE, Lee Jones, Srinivas Pandruvada, Aaron Lu,
	Alan Cox, Jean Delvare, Samuel Ortiz, Liam Girdwood,
	Grant Likely, Greg Kroah-Hartman, Rob Herring,
	Lars-Peter Clausen, Hartmut Knaack, Fugang Duan, Arnd Bergmann,
	Zubair Lutfullah, Sebastian Reichel, Johannes Thumshirn,
	Philippe Reynes, Angelo Compagnucci, Doug Anderson

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

On Thu, Sep 11, 2014 at 03:26:50PM -0700, Jacob Pan wrote:
> Mark Brown <broonie@debian.org> wrote:

> > but is it really worth the effort of renaming everything?  That's
> > going to cause problems for things like the stable workflow.

> sorry for the late reply. IMHO, consistent and correct naming has
> longer term benefit. how can i help to make the stable workflow easier?

Not do the rename - it makes doing a git cherry-pick easier.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2014-09-12  7:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-08 22:24 [PATCH 0/4] Initial support for XPowers AXP288 PMIC Jacob Pan
2014-09-08 22:24 ` [PATCH 1/4] mfd/axp20x: rename files to support more devices Jacob Pan
2014-09-09  8:11   ` Lee Jones
2014-09-08 22:24 ` [PATCH 2/4] mfd/axp2xx: extend axp20x to support axp288 pmic Jacob Pan
2014-09-09  7:37   ` Maxime Ripard
2014-09-09 12:45     ` Jacob Pan
2014-09-09 13:37       ` Maxime Ripard
2014-09-11 22:23         ` Jacob Pan
2014-09-08 22:24 ` [PATCH 3/4] regulator/axp20x: use axp2xx consolidated header Jacob Pan
2014-09-09 11:25   ` Mark Brown
2014-09-11 22:26     ` Jacob Pan
2014-09-12  7:39       ` Mark Brown
2014-09-08 22:24 ` [PATCH 4/4] iio/adc/axp288: add support for axp288 gpadc Jacob Pan
2014-09-10  4:19   ` Pallala, Ramakrishna

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).