linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997
@ 2012-02-23 12:38 Thomas Abraham
  2012-02-23 12:38 ` [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts Thomas Abraham
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Thomas Abraham @ 2012-02-23 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, grant.likely,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc

Changes since v2:
- Atleast one voltage level has to be specfied for Buck 1/2/5 even if GPIO
  DVS option is not used (suggested by MyungJoo Ham).
- Reworked the irq_domain support based the v5 of irq_domain generalization
  patches.

MAX8997 is a multi-function device which includes support for regulators, rtc,
battery charger and other sub-blocks. This patchset adds device tree support
for the pmic (regulators) sub-block.

The first patch adds irq domain support for the interrupts supported by max8997
mainly for removing the need to pass a irq_base from the platform code. The
irq_base could not anyway be passed in case of device tree based instantiation.
The reverse mapping method used is linear since the sub-drivers of max8997 has
access to the max8997 irq_domain from which the linux irq number can be
obtained.

The second patch adds device tree support for max8997. This patch modifies both
mfd and regulator portions of the max8997 code.

This patchset is based on the following tree.
http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git [for-next]

with all patches merged from
http://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git [for-next]
http://git.secretlab.ca/git/linux-2.6.git [irqdomain/next]

and depends on the following patchset.
[PATCH v3 0/4] ARM: Exynos4: Add irq domain and device tree support for wakeup interrupts.

This patchset has been tested on Origen board.

Thomas Abraham (2):
  mfd: add irq domain support for max8997 interrupts
  regulator: add device tree support for max8997

 .../devicetree/bindings/regulator/max8997-pmic.txt |  134 +++++++++++++++++++
 arch/arm/mach-exynos/mach-nuri.c                   |    4 -
 arch/arm/mach-exynos/mach-origen.c                 |    1 -
 drivers/mfd/max8997-irq.c                          |   60 +++++----
 drivers/mfd/max8997.c                              |   73 ++++++++++-
 drivers/regulator/max8997.c                        |  139 +++++++++++++++++++-
 include/linux/mfd/max8997-private.h                |    4 +-
 include/linux/mfd/max8997.h                        |    2 +-
 8 files changed, 382 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/regulator/max8997-pmic.txt


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

* [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts
  2012-02-23 12:38 [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
@ 2012-02-23 12:38 ` Thomas Abraham
  2012-03-13  3:28   ` Grant Likely
  2012-02-23 12:38 ` [PATCH v3 2/2] regulator: add device tree support for max8997 Thomas Abraham
  2012-03-12 21:10 ` [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
  2 siblings, 1 reply; 10+ messages in thread
From: Thomas Abraham @ 2012-02-23 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, grant.likely,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc

Add irq domain support for max8997 interrupts. The reverse mapping method
used is linear mapping since the sub-drivers of max8997 such as regulator
and charger drivers can use the max8997 irq_domain to get the linux irq
number for max8997 interrupts. All uses of irq_base in platform data and
max8997 driver private data are removed.

Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 arch/arm/mach-exynos/mach-nuri.c    |    4 --
 arch/arm/mach-exynos/mach-origen.c  |    1 -
 drivers/mfd/max8997-irq.c           |   60 ++++++++++++++++++++--------------
 drivers/mfd/max8997.c               |    1 -
 include/linux/mfd/max8997-private.h |    4 ++-
 include/linux/mfd/max8997.h         |    1 -
 6 files changed, 38 insertions(+), 33 deletions(-)

diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index a6b9162..1e9ba12 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -1078,12 +1078,8 @@ static struct platform_device nuri_max8903_device = {
 static void __init nuri_power_init(void)
 {
 	int gpio;
-	int irq_base = IRQ_GPIO_END + 1;
 	int ta_en = 0;
 
-	nuri_max8997_pdata.irq_base = irq_base;
-	irq_base += MAX8997_IRQ_NR;
-
 	gpio = EXYNOS4_GPX0(7);
 	gpio_request(gpio, "AP_PMIC_IRQ");
 	s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 02c242e..328dadb 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -424,7 +424,6 @@ static struct max8997_platform_data __initdata origen_max8997_pdata = {
 	.buck1_gpiodvs	= false,
 	.buck2_gpiodvs	= false,
 	.buck5_gpiodvs	= false,
-	.irq_base	= IRQ_GPIO_END + 1,
 
 	.ignore_gpiodvs_side_effect = true,
 	.buck125_default_idx = 0x0,
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c
index 09274cf..3d8c9d1 100644
--- a/drivers/mfd/max8997-irq.c
+++ b/drivers/mfd/max8997-irq.c
@@ -142,7 +142,8 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
 static const inline struct max8997_irq_data *
 irq_to_max8997_irq(struct max8997_dev *max8997, int irq)
 {
-	return &max8997_irqs[irq - max8997->irq_base];
+	struct irq_data *data = irq_get_irq_data(irq);
+	return &max8997_irqs[data->hwirq];
 }
 
 static void max8997_irq_mask(struct irq_data *data)
@@ -182,7 +183,7 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
 	u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {};
 	u8 irq_src;
 	int ret;
-	int i;
+	int i, cur_irq;
 
 	ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src);
 	if (ret < 0) {
@@ -269,8 +270,10 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
 
 	/* Report */
 	for (i = 0; i < MAX8997_IRQ_NR; i++) {
-		if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask)
-			handle_nested_irq(max8997->irq_base + i);
+		if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) {
+			cur_irq = irq_find_mapping(max8997->irq_domain, i);
+			handle_nested_irq(cur_irq);
+		}
 	}
 
 	return IRQ_HANDLED;
@@ -278,26 +281,40 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
 
 int max8997_irq_resume(struct max8997_dev *max8997)
 {
-	if (max8997->irq && max8997->irq_base)
-		max8997_irq_thread(max8997->irq_base, max8997);
+	if (max8997->irq && max8997->irq_domain)
+		max8997_irq_thread(0, max8997);
+	return 0;
+}
+
+static int max8997_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	struct max8997_dev *max8997 = d->host_data;
+
+	irq_set_chip_data(irq, max8997);
+	irq_set_chip_and_handler(irq, &max8997_irq_chip, handle_edge_irq);
+	irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+	set_irq_flags(irq, IRQF_VALID);
+#else
+	irq_set_noprobe(irq);
+#endif
 	return 0;
 }
 
+static struct irq_domain_ops max8997_irq_domain_ops = {
+	.map = max8997_irq_domain_map,
+};
+
 int max8997_irq_init(struct max8997_dev *max8997)
 {
+	struct irq_domain *domain;
 	int i;
-	int cur_irq;
 	int ret;
 	u8 val;
 
 	if (!max8997->irq) {
 		dev_warn(max8997->dev, "No interrupt specified.\n");
-		max8997->irq_base = 0;
-		return 0;
-	}
-
-	if (!max8997->irq_base) {
-		dev_err(max8997->dev, "No interrupt base specified.\n");
 		return 0;
 	}
 
@@ -327,18 +344,11 @@ int max8997_irq_init(struct max8997_dev *max8997)
 					true : false;
 	}
 
-	/* Register with genirq */
-	for (i = 0; i < MAX8997_IRQ_NR; i++) {
-		cur_irq = i + max8997->irq_base;
-		irq_set_chip_data(cur_irq, max8997);
-		irq_set_chip_and_handler(cur_irq, &max8997_irq_chip,
-				handle_edge_irq);
-		irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
-		set_irq_flags(cur_irq, IRQF_VALID);
-#else
-		irq_set_noprobe(cur_irq);
-#endif
+	domain = irq_domain_add_linear(NULL, MAX8997_IRQ_NR,
+					&max8997_irq_domain_ops, &max8997);
+	if (!domain) {
+		dev_err(max8997->dev, "could not create irq domain\n");
+		return -ENODEV;
 	}
 
 	ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread,
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index cb83a7a..20ecad3 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -143,7 +143,6 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
 	if (!pdata)
 		goto err;
 
-	max8997->irq_base = pdata->irq_base;
 	max8997->ono = pdata->ono;
 
 	mutex_init(&max8997->iolock);
diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h
index 3f4deb6..830152c 100644
--- a/include/linux/mfd/max8997-private.h
+++ b/include/linux/mfd/max8997-private.h
@@ -23,6 +23,8 @@
 #define __LINUX_MFD_MAX8997_PRIV_H
 
 #include <linux/i2c.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
 
 #define MAX8997_REG_INVALID	(0xff)
 
@@ -325,7 +327,7 @@ struct max8997_dev {
 
 	int irq;
 	int ono;
-	int irq_base;
+	struct irq_domain *irq_domain;
 	struct mutex irqlock;
 	int irq_masks_cur[MAX8997_IRQ_GROUP_NR];
 	int irq_masks_cache[MAX8997_IRQ_GROUP_NR];
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
index fff5905..818486c 100644
--- a/include/linux/mfd/max8997.h
+++ b/include/linux/mfd/max8997.h
@@ -155,7 +155,6 @@ struct max8997_led_platform_data {
 
 struct max8997_platform_data {
 	/* IRQ */
-	int irq_base;
 	int ono;
 	int wakeup;
 
-- 
1.6.6.rc2


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

* [PATCH v3 2/2] regulator: add device tree support for max8997
  2012-02-23 12:38 [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
  2012-02-23 12:38 ` [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts Thomas Abraham
@ 2012-02-23 12:38 ` Thomas Abraham
  2012-03-13  3:43   ` Grant Likely
  2012-03-12 21:10 ` [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
  2 siblings, 1 reply; 10+ messages in thread
From: Thomas Abraham @ 2012-02-23 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, grant.likely,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc, Rajendra Nayak

Add device tree based discovery support for max8997.

Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 .../devicetree/bindings/regulator/max8997-pmic.txt |  134 +++++++++++++++++++
 drivers/mfd/max8997.c                              |   72 ++++++++++-
 drivers/regulator/max8997.c                        |  139 +++++++++++++++++++-
 include/linux/mfd/max8997.h                        |    1 +
 4 files changed, 344 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/regulator/max8997-pmic.txt

diff --git a/Documentation/devicetree/bindings/regulator/max8997-pmic.txt b/Documentation/devicetree/bindings/regulator/max8997-pmic.txt
new file mode 100644
index 0000000..d282635
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/max8997-pmic.txt
@@ -0,0 +1,134 @@
+* Maxim MAX8997 Voltage and Current Regulator
+
+The Maxim MAX8997 is a multi-function device which includes volatage and
+current regulators, rtc, charger controller and other sub-blocks. It is
+interfaced to the host controller using a i2c interface. Each sub-block is
+addressed by the host system using different i2c slave address. This document
+describes the bindings for 'pmic' sub-block of max8997.
+
+Required properties:
+- compatible: Should be "maxim,max8997-pmic".
+- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
+
+- max8997,pmic-buck1-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck1 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+- max8997,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck2 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+- max8997,pmic-buck5-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+  units for buck5 when changing voltage using gpio dvs. Refer to [1] below
+  for additional information.
+
+[1] If none of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional
+    property is specified, the 'max8997,pmic-buck[1/2/5]-dvs-voltage'
+    property should specify atleast one voltage level (which would be a
+    safe operating voltage).
+
+    If either of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional
+    property is specified, then all the eigth voltage values for the
+    'max8997,pmic-buck[1/2/5]-dvs-voltage' should be specified.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the interrupts from max8997 are delivered to.
+- interrupts: Interrupt specifiers for two interrupt sources.
+  - First interrupt specifier is for 'irq1' interrupt.
+  - Second interrupt specifier is for 'alert' interrupt.
+- max8997,pmic-buck1-uses-gpio-dvs: 'buck1' can be controlled by gpio dvs.
+- max8997,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
+- max8997,pmic-buck5-uses-gpio-dvs: 'buck5' can be controlled by gpio dvs.
+
+Additional properties required if either of the optional properties are used:
+- max8997,pmic-ignore-gpiodvs-side-effect: When GPIO-DVS mode is used for
+  multiple bucks, changing the voltage value of one of the bucks may affect
+  that of another buck, which is the side effect of the change (set_voltage).
+  Use this property to ignore such side effects and change the voltage.
+
+- max8997,pmic-buck125-default-dvs-idx: Default voltage setting selected from
+  the possible 8 options selectable by the dvs gpios. The value of this
+  property should be between 0 and 7. If not specified or if out of range, the
+  default value of this property is set to 0.
+
+- max8997,pmic-buck125-dvs-gpios: GPIO specifiers for three host gpio's used
+  for dvs. The format of the gpio specifier depends in the gpio controller.
+
+
+Regulators: The regulators of max8997 that have to be instantiated should be
+included in a sub-node named 'regulators'. Regulator nodes included in this
+sub-node should be of the format as below. Note: The 'n' in LDOn and BUCKn
+represents the LDO or BUCK number as per the datasheet of max8997.
+
+    For LDO's:
+		LDOn {
+			standard regulator bindings here
+		};
+
+    For BUCK's:
+		BUCKn {
+			standard regulator bindings here
+		};
+
+The bindings inside the regulator nodes use the standard regulator bindings
+which are documented elsewhere.
+
+Example:
+
+	max8997_pmic@66 {
+		compatible = "maxim,max8997-pmic";
+		interrupt-parent = <&wakeup_eint>;
+		reg = <0x66>;
+		interrupts = <4 0>, <3 0>;
+
+		max8997,pmic-buck1-uses-gpio-dvs;
+		max8997,pmic-buck2-uses-gpio-dvs;
+		max8997,pmic-buck5-uses-gpio-dvs;
+
+		max8997,pmic-ignore-gpiodvs-side-effect;
+		max8997,pmic-buck125-default-dvs-idx = <0>;
+
+		max8997,pmic-buck125-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */
+						 <&gpx0 1 1 0 0>, /* SET2 */
+						 <&gpx0 2 1 0 0>; /* SET3 */
+
+		max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
+						 <1250000>, <1200000>,
+						 <1150000>, <1100000>,
+						 <1000000>, <950000>;
+
+		max8997,pmic-buck2-dvs-voltage = <1100000>, <1100000>,
+				    		 <1100000>, <1100000>,
+						 <1000000>, <1000000>,
+						 <1000000>, <1000000>;
+
+		max8997,pmic-buck5-dvs-voltage = <1200000>, <1200000>,
+						 <1200000>, <1200000>,
+						 <1200000>, <1200000>,
+						 <1200000>, <1200000>;
+
+		regulators {
+			ldo1_reg: LDO1 {
+				regulator-name = "VDD_ABB_3.3V";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "VDD_ALIVE_1.1V";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+			};
+
+			buck1_reg: BUCK1 {
+				regulator-name = "VDD_ARM_1.2V";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+		};
+	};
+
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 20ecad3..13180be 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -23,6 +23,7 @@
 
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/of_irq.h>
 #include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
@@ -123,6 +124,60 @@ int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
 }
 EXPORT_SYMBOL_GPL(max8997_update_reg);
 
+#ifdef CONFIG_OF
+/*
+ * Only the common platform data elements for max8997 are parsed here from the
+ * device tree. Other sub-modules of max8997 such as pmic, rtc and others have
+ * to parse their own platform data elements from device tree.
+ *
+ * The max8997 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static int max8997_i2c_parse_dt_pdata(struct device *dev,
+					struct max8997_platform_data **pdata)
+{
+	struct max8997_platform_data *pd;
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return -ENOMEM;
+	}
+
+	pd->ono = irq_of_parse_and_map(dev->of_node, 1);
+
+	/*
+	 * ToDo: the 'wakeup' member in the platform data is more of a linux
+	 * specfic information. Hence, there is no binding for that yet and
+	 * not parsed here.
+	 */
+
+	*pdata = pd;
+	return 0;
+}
+#else
+static int max8997_i2c_parse_dt_pdata(struct device *dev,
+					struct max8997_platform_data **pdata)
+{
+	return 0;
+}
+#endif
+
+static struct of_device_id __devinitdata max8997_pmic_dt_match[];
+static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
+						const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
+		return (int)match->data;
+	}
+#endif
+	return (int)id->driver_data;
+}
+
 static int max8997_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -137,9 +192,16 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
 	i2c_set_clientdata(i2c, max8997);
 	max8997->dev = &i2c->dev;
 	max8997->i2c = i2c;
-	max8997->type = id->driver_data;
+	max8997->type = max8997_i2c_get_driver_data(i2c, id);
 	max8997->irq = i2c->irq;
 
+	if (max8997->dev->of_node) {
+		ret = max8997_i2c_parse_dt_pdata(max8997->dev, &pdata);
+		if (ret)
+			goto err;
+		i2c->dev.platform_data = pdata;
+	}
+
 	if (!pdata)
 		goto err;
 
@@ -429,11 +491,19 @@ const struct dev_pm_ops max8997_pm = {
 	.restore = max8997_restore,
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id __devinitdata max8997_pmic_dt_match[] = {
+	{ .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 },
+	{},
+};
+#endif
+
 static struct i2c_driver max8997_i2c_driver = {
 	.driver = {
 		   .name = "max8997",
 		   .owner = THIS_MODULE,
 		   .pm = &max8997_pm,
+		   .of_match_table = of_match_ptr(max8997_pmic_dt_match),
 	},
 	.probe = max8997_i2c_probe,
 	.remove = max8997_i2c_remove,
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index bb7cd9d..b31c4c9 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -32,6 +33,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/max8997.h>
 #include <linux/mfd/max8997-private.h>
+#include <linux/regulator/of_regulator.h>
 
 struct max8997_data {
 	struct device *dev;
@@ -958,6 +960,134 @@ static struct regulator_desc regulators[] = {
 	},
 };
 
+#ifdef CONFIG_OF
+static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
+			struct max8997_platform_data *pdata,
+			struct device_node *pmic_np)
+{
+	int i, gpio;
+
+	for (i = 0; i < 3; i++) {
+		gpio = of_get_named_gpio(pmic_np,
+					"max8997,pmic-buck125-dvs-gpios", i);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+			return -EINVAL;
+		}
+		pdata->buck125_gpios[i] = gpio;
+	}
+	return 0;
+}
+
+static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+					struct max8997_platform_data *pdata)
+{
+	struct device_node *pmic_np, *regulators_np, *reg_np;
+	struct max8997_regulator_data *rdata;
+	unsigned int i, dvs_voltage_nr = 1, ret;
+
+	pmic_np = iodev->dev->of_node;
+	if (!pmic_np) {
+		dev_err(iodev->dev, "could not find pmic sub-node\n");
+		return -ENODEV;
+	}
+
+	regulators_np = of_find_node_by_name(pmic_np, "regulators");
+	if (!regulators_np) {
+		dev_err(iodev->dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	/* count the number of regulators to be supported in pmic */
+	pdata->num_regulators = 0;
+	for_each_child_of_node(regulators_np, reg_np)
+		pdata->num_regulators++;
+
+	rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+				pdata->num_regulators, GFP_KERNEL);
+	if (!rdata) {
+		dev_err(iodev->dev, "could not allocate memory for "
+						"regulator data\n");
+		return -ENOMEM;
+	}
+
+	pdata->regulators = rdata;
+	for_each_child_of_node(regulators_np, reg_np) {
+		for (i = 0; i < ARRAY_SIZE(regulators); i++)
+			if (!of_node_cmp(reg_np->name, regulators[i].name))
+				break;
+		rdata->id = i;
+		rdata->initdata = of_get_regulator_init_data(
+						iodev->dev, reg_np);
+		rdata->reg_node = reg_np;
+		rdata++;
+	}
+
+	if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
+		pdata->buck1_gpiodvs = true;
+
+	if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL))
+		pdata->buck2_gpiodvs = true;
+
+	if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL))
+		pdata->buck5_gpiodvs = true;
+
+	if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
+						pdata->buck5_gpiodvs) {
+		ret = max8997_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+		if (ret)
+			return -EINVAL;
+
+		if (of_property_read_u32(pmic_np,
+				"max8997,pmic-buck125-default-dvs-idx",
+				&pdata->buck125_default_idx)) {
+			pdata->buck125_default_idx = 0;
+		} else {
+			if (pdata->buck125_default_idx >= 8) {
+				pdata->buck125_default_idx = 0;
+				dev_info(iodev->dev, "invalid value for "
+				"default dvs index, using 0 instead\n");
+			}
+		}
+
+		if (of_get_property(pmic_np,
+			"max8997,pmic-ignore-gpiodvs-side-effect", NULL))
+			pdata->ignore_gpiodvs_side_effect = true;
+
+		dvs_voltage_nr = 8;
+	}
+
+	if (of_property_read_u32_array(pmic_np,
+				"max8997,pmic-buck1-dvs-voltage",
+				pdata->buck1_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck1 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32_array(pmic_np,
+				"max8997,pmic-buck2-dvs-voltage",
+				pdata->buck2_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck2 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32_array(pmic_np,
+				"max8997,pmic-buck5-dvs-voltage",
+				pdata->buck5_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck5 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+					struct max8997_platform_data *pdata)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
 static __devinit int max8997_pmic_probe(struct platform_device *pdev)
 {
 	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
@@ -968,6 +1098,12 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
 	int i, ret, size;
 	u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
 
+	if (iodev->dev->of_node) {
+		ret = max8997_pmic_dt_parse_pdata(iodev, pdata);
+		if (ret)
+			return ret;
+	}
+
 	if (!pdata) {
 		dev_err(pdev->dev.parent, "No platform init data supplied.\n");
 		return -ENODEV;
@@ -1146,7 +1282,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
 			regulators[id].n_voltages = 16;
 
 		rdev[i] = regulator_register(&regulators[id], max8997->dev,
-				pdata->regulators[i].initdata, max8997, NULL);
+				pdata->regulators[i].initdata, max8997,
+				pdata->regulators[i].reg_node);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
 			dev_err(max8997->dev, "regulator init failed for %d\n",
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
index 818486c..ba92375 100644
--- a/include/linux/mfd/max8997.h
+++ b/include/linux/mfd/max8997.h
@@ -75,6 +75,7 @@ enum max8998_regulators {
 struct max8997_regulator_data {
 	int id;
 	struct regulator_init_data *initdata;
+	struct device_node *reg_node;
 };
 
 enum max8997_muic_usb_type {
-- 
1.6.6.rc2


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

* Re: [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997
  2012-02-23 12:38 [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
  2012-02-23 12:38 ` [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts Thomas Abraham
  2012-02-23 12:38 ` [PATCH v3 2/2] regulator: add device tree support for max8997 Thomas Abraham
@ 2012-03-12 21:10 ` Thomas Abraham
  2 siblings, 0 replies; 10+ messages in thread
From: Thomas Abraham @ 2012-03-12 21:10 UTC (permalink / raw)
  To: linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, grant.likely,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc

Hi Rob/Grant,

On 23 February 2012 18:08, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Changes since v2:
> - Atleast one voltage level has to be specfied for Buck 1/2/5 even if GPIO
>  DVS option is not used (suggested by MyungJoo Ham).
> - Reworked the irq_domain support based the v5 of irq_domain generalization
>  patches.
>
> MAX8997 is a multi-function device which includes support for regulators, rtc,
> battery charger and other sub-blocks. This patchset adds device tree support
> for the pmic (regulators) sub-block.
>
> The first patch adds irq domain support for the interrupts supported by max8997
> mainly for removing the need to pass a irq_base from the platform code. The
> irq_base could not anyway be passed in case of device tree based instantiation.
> The reverse mapping method used is linear since the sub-drivers of max8997 has
> access to the max8997 irq_domain from which the linux irq number can be
> obtained.
>
> The second patch adds device tree support for max8997. This patch modifies both
> mfd and regulator portions of the max8997 code.
>
> This patchset is based on the following tree.
> http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git [for-next]
>
> with all patches merged from
> http://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git [for-next]
> http://git.secretlab.ca/git/linux-2.6.git [irqdomain/next]
>
> and depends on the following patchset.
> [PATCH v3 0/4] ARM: Exynos4: Add irq domain and device tree support for wakeup interrupts.
>
> This patchset has been tested on Origen board.
>
> Thomas Abraham (2):
>  mfd: add irq domain support for max8997 interrupts
>  regulator: add device tree support for max8997

Any comments for this patch series?

Thanks,
Thomas.

>
>  .../devicetree/bindings/regulator/max8997-pmic.txt |  134 +++++++++++++++++++
>  arch/arm/mach-exynos/mach-nuri.c                   |    4 -
>  arch/arm/mach-exynos/mach-origen.c                 |    1 -
>  drivers/mfd/max8997-irq.c                          |   60 +++++----
>  drivers/mfd/max8997.c                              |   73 ++++++++++-
>  drivers/regulator/max8997.c                        |  139 +++++++++++++++++++-
>  include/linux/mfd/max8997-private.h                |    4 +-
>  include/linux/mfd/max8997.h                        |    2 +-
>  8 files changed, 382 insertions(+), 35 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/regulator/max8997-pmic.txt
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts
  2012-02-23 12:38 ` [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts Thomas Abraham
@ 2012-03-13  3:28   ` Grant Likely
  2012-03-13  6:05     ` Thomas Abraham
  0 siblings, 1 reply; 10+ messages in thread
From: Grant Likely @ 2012-03-13  3:28 UTC (permalink / raw)
  To: Thomas Abraham, linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, kgene.kim,
	broonie, myungjoo.ham, kyungmin.park, dg77.kim, linux-arm-kernel,
	linux-samsung-soc

On Thu, 23 Feb 2012 18:08:07 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Add irq domain support for max8997 interrupts. The reverse mapping method
> used is linear mapping since the sub-drivers of max8997 such as regulator
> and charger drivers can use the max8997 irq_domain to get the linux irq
> number for max8997 interrupts. All uses of irq_base in platform data and
> max8997 driver private data are removed.
> 
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  arch/arm/mach-exynos/mach-nuri.c    |    4 --
>  arch/arm/mach-exynos/mach-origen.c  |    1 -
>  drivers/mfd/max8997-irq.c           |   60 ++++++++++++++++++++--------------
>  drivers/mfd/max8997.c               |    1 -
>  include/linux/mfd/max8997-private.h |    4 ++-
>  include/linux/mfd/max8997.h         |    1 -
>  6 files changed, 38 insertions(+), 33 deletions(-)

Nice patch.  Nice diffstat too.  Some comments below, but I'm happy with where
this is at.

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> 
> diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
> index a6b9162..1e9ba12 100644
> --- a/arch/arm/mach-exynos/mach-nuri.c
> +++ b/arch/arm/mach-exynos/mach-nuri.c
> @@ -1078,12 +1078,8 @@ static struct platform_device nuri_max8903_device = {
>  static void __init nuri_power_init(void)
>  {
>  	int gpio;
> -	int irq_base = IRQ_GPIO_END + 1;
>  	int ta_en = 0;
>  
> -	nuri_max8997_pdata.irq_base = irq_base;
> -	irq_base += MAX8997_IRQ_NR;
> -
>  	gpio = EXYNOS4_GPX0(7);
>  	gpio_request(gpio, "AP_PMIC_IRQ");
>  	s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
> diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
> index 02c242e..328dadb 100644
> --- a/arch/arm/mach-exynos/mach-origen.c
> +++ b/arch/arm/mach-exynos/mach-origen.c
> @@ -424,7 +424,6 @@ static struct max8997_platform_data __initdata origen_max8997_pdata = {
>  	.buck1_gpiodvs	= false,
>  	.buck2_gpiodvs	= false,
>  	.buck5_gpiodvs	= false,
> -	.irq_base	= IRQ_GPIO_END + 1,
>  
>  	.ignore_gpiodvs_side_effect = true,
>  	.buck125_default_idx = 0x0,
> diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c
> index 09274cf..3d8c9d1 100644
> --- a/drivers/mfd/max8997-irq.c
> +++ b/drivers/mfd/max8997-irq.c
> @@ -142,7 +142,8 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
>  static const inline struct max8997_irq_data *
>  irq_to_max8997_irq(struct max8997_dev *max8997, int irq)
>  {
> -	return &max8997_irqs[irq - max8997->irq_base];
> +	struct irq_data *data = irq_get_irq_data(irq);
> +	return &max8997_irqs[data->hwirq];

Hahaha.  The max8997_irqs table is kind of overdone when the group and mask values
can be arithmetically derived from the hwirq number..

This change is fine, but the driver could use some refactoring.  :-)

>  }
>  
>  static void max8997_irq_mask(struct irq_data *data)
> @@ -182,7 +183,7 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
>  	u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {};
>  	u8 irq_src;
>  	int ret;
> -	int i;
> +	int i, cur_irq;
>  
>  	ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src);
>  	if (ret < 0) {
> @@ -269,8 +270,10 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
>  
>  	/* Report */
>  	for (i = 0; i < MAX8997_IRQ_NR; i++) {
> -		if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask)
> -			handle_nested_irq(max8997->irq_base + i);
> +		if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) {
> +			cur_irq = irq_find_mapping(max8997->irq_domain, i);
> +			handle_nested_irq(cur_irq);
> +		}

Well, if you're using the linear mapping, then only actually allocated irqs will
have a mapping set up.  So the driver could simply do:

	for (i = 0; i < MAX8997_IRQ_NR; i++) {
		cur_irq = irq_find_mapping(max8997->irq_domain, i);
		if (cur_irq)
			handle_nested_irq(cur_irq);
	}

>  	}
>  
>  	return IRQ_HANDLED;
> @@ -278,26 +281,40 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
>  
>  int max8997_irq_resume(struct max8997_dev *max8997)
>  {
> -	if (max8997->irq && max8997->irq_base)
> -		max8997_irq_thread(max8997->irq_base, max8997);
> +	if (max8997->irq && max8997->irq_domain)
> +		max8997_irq_thread(0, max8997);
> +	return 0;
> +}
> +
> +static int max8997_irq_domain_map(struct irq_domain *d, unsigned int irq,
> +					irq_hw_number_t hw)
> +{
> +	struct max8997_dev *max8997 = d->host_data;
> +
> +	irq_set_chip_data(irq, max8997);
> +	irq_set_chip_and_handler(irq, &max8997_irq_chip, handle_edge_irq);
> +	irq_set_nested_thread(irq, 1);
> +#ifdef CONFIG_ARM
> +	set_irq_flags(irq, IRQF_VALID);
> +#else
> +	irq_set_noprobe(irq);
> +#endif
>  	return 0;
>  }
>  
> +static struct irq_domain_ops max8997_irq_domain_ops = {
> +	.map = max8997_irq_domain_map,
> +};
> +
>  int max8997_irq_init(struct max8997_dev *max8997)
>  {
> +	struct irq_domain *domain;
>  	int i;
> -	int cur_irq;
>  	int ret;
>  	u8 val;
>  
>  	if (!max8997->irq) {
>  		dev_warn(max8997->dev, "No interrupt specified.\n");
> -		max8997->irq_base = 0;
> -		return 0;
> -	}
> -
> -	if (!max8997->irq_base) {
> -		dev_err(max8997->dev, "No interrupt base specified.\n");
>  		return 0;
>  	}
>  
> @@ -327,18 +344,11 @@ int max8997_irq_init(struct max8997_dev *max8997)
>  					true : false;
>  	}
>  
> -	/* Register with genirq */
> -	for (i = 0; i < MAX8997_IRQ_NR; i++) {
> -		cur_irq = i + max8997->irq_base;
> -		irq_set_chip_data(cur_irq, max8997);
> -		irq_set_chip_and_handler(cur_irq, &max8997_irq_chip,
> -				handle_edge_irq);
> -		irq_set_nested_thread(cur_irq, 1);
> -#ifdef CONFIG_ARM
> -		set_irq_flags(cur_irq, IRQF_VALID);
> -#else
> -		irq_set_noprobe(cur_irq);
> -#endif
> +	domain = irq_domain_add_linear(NULL, MAX8997_IRQ_NR,
> +					&max8997_irq_domain_ops, &max8997);
> +	if (!domain) {
> +		dev_err(max8997->dev, "could not create irq domain\n");
> +		return -ENODEV;
>  	}
>  
>  	ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread,
> diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
> index cb83a7a..20ecad3 100644
> --- a/drivers/mfd/max8997.c
> +++ b/drivers/mfd/max8997.c
> @@ -143,7 +143,6 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
>  	if (!pdata)
>  		goto err;
>  
> -	max8997->irq_base = pdata->irq_base;
>  	max8997->ono = pdata->ono;
>  
>  	mutex_init(&max8997->iolock);
> diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h
> index 3f4deb6..830152c 100644
> --- a/include/linux/mfd/max8997-private.h
> +++ b/include/linux/mfd/max8997-private.h
> @@ -23,6 +23,8 @@
>  #define __LINUX_MFD_MAX8997_PRIV_H
>  
>  #include <linux/i2c.h>
> +#include <linux/export.h>
> +#include <linux/irqdomain.h>
>  
>  #define MAX8997_REG_INVALID	(0xff)
>  
> @@ -325,7 +327,7 @@ struct max8997_dev {
>  
>  	int irq;
>  	int ono;
> -	int irq_base;
> +	struct irq_domain *irq_domain;
>  	struct mutex irqlock;
>  	int irq_masks_cur[MAX8997_IRQ_GROUP_NR];
>  	int irq_masks_cache[MAX8997_IRQ_GROUP_NR];
> diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
> index fff5905..818486c 100644
> --- a/include/linux/mfd/max8997.h
> +++ b/include/linux/mfd/max8997.h
> @@ -155,7 +155,6 @@ struct max8997_led_platform_data {
>  
>  struct max8997_platform_data {
>  	/* IRQ */
> -	int irq_base;
>  	int ono;
>  	int wakeup;
>  
> -- 
> 1.6.6.rc2
> 

-- 
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies,Ltd.

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

* Re: [PATCH v3 2/2] regulator: add device tree support for max8997
  2012-02-23 12:38 ` [PATCH v3 2/2] regulator: add device tree support for max8997 Thomas Abraham
@ 2012-03-13  3:43   ` Grant Likely
  2012-03-13  6:44     ` Thomas Abraham
  0 siblings, 1 reply; 10+ messages in thread
From: Grant Likely @ 2012-03-13  3:43 UTC (permalink / raw)
  To: Thomas Abraham, linux-kernel
  Cc: k.lewandowsk, devicetree-discuss, rob.herring, kgene.kim,
	broonie, myungjoo.ham, kyungmin.park, dg77.kim, linux-arm-kernel,
	linux-samsung-soc, Rajendra Nayak

On Thu, 23 Feb 2012 18:08:08 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Add device tree based discovery support for max8997.
> 
> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
> Cc: Rajendra Nayak <rnayak@ti.com>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  .../devicetree/bindings/regulator/max8997-pmic.txt |  134 +++++++++++++++++++
>  drivers/mfd/max8997.c                              |   72 ++++++++++-
>  drivers/regulator/max8997.c                        |  139 +++++++++++++++++++-
>  include/linux/mfd/max8997.h                        |    1 +
>  4 files changed, 344 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/regulator/max8997-pmic.txt
> 
> diff --git a/Documentation/devicetree/bindings/regulator/max8997-pmic.txt b/Documentation/devicetree/bindings/regulator/max8997-pmic.txt
> new file mode 100644
> index 0000000..d282635
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/max8997-pmic.txt
> @@ -0,0 +1,134 @@
> +* Maxim MAX8997 Voltage and Current Regulator
> +
> +The Maxim MAX8997 is a multi-function device which includes volatage and
> +current regulators, rtc, charger controller and other sub-blocks. It is
> +interfaced to the host controller using a i2c interface. Each sub-block is
> +addressed by the host system using different i2c slave address. This document
> +describes the bindings for 'pmic' sub-block of max8997.
> +
> +Required properties:
> +- compatible: Should be "maxim,max8997-pmic".
> +- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
> +
> +- max8997,pmic-buck1-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
> +  units for buck1 when changing voltage using gpio dvs. Refer to [1] below
> +  for additional information.
> +
> +- max8997,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
> +  units for buck2 when changing voltage using gpio dvs. Refer to [1] below
> +  for additional information.
> +
> +- max8997,pmic-buck5-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
> +  units for buck5 when changing voltage using gpio dvs. Refer to [1] below
> +  for additional information.
> +
> +[1] If none of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional
> +    property is specified, the 'max8997,pmic-buck[1/2/5]-dvs-voltage'
> +    property should specify atleast one voltage level (which would be a
> +    safe operating voltage).
> +
> +    If either of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional
> +    property is specified, then all the eigth voltage values for the
> +    'max8997,pmic-buck[1/2/5]-dvs-voltage' should be specified.
> +
> +Optional properties:
> +- interrupt-parent: Specifies the phandle of the interrupt controller to which
> +  the interrupts from max8997 are delivered to.
> +- interrupts: Interrupt specifiers for two interrupt sources.
> +  - First interrupt specifier is for 'irq1' interrupt.
> +  - Second interrupt specifier is for 'alert' interrupt.
> +- max8997,pmic-buck1-uses-gpio-dvs: 'buck1' can be controlled by gpio dvs.
> +- max8997,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
> +- max8997,pmic-buck5-uses-gpio-dvs: 'buck5' can be controlled by gpio dvs.
> +
> +Additional properties required if either of the optional properties are used:
> +- max8997,pmic-ignore-gpiodvs-side-effect: When GPIO-DVS mode is used for
> +  multiple bucks, changing the voltage value of one of the bucks may affect
> +  that of another buck, which is the side effect of the change (set_voltage).
> +  Use this property to ignore such side effects and change the voltage.
> +
> +- max8997,pmic-buck125-default-dvs-idx: Default voltage setting selected from
> +  the possible 8 options selectable by the dvs gpios. The value of this
> +  property should be between 0 and 7. If not specified or if out of range, the
> +  default value of this property is set to 0.
> +
> +- max8997,pmic-buck125-dvs-gpios: GPIO specifiers for three host gpio's used
> +  for dvs. The format of the gpio specifier depends in the gpio controller.
> +
> +
> +Regulators: The regulators of max8997 that have to be instantiated should be
> +included in a sub-node named 'regulators'. Regulator nodes included in this
> +sub-node should be of the format as below. Note: The 'n' in LDOn and BUCKn
> +represents the LDO or BUCK number as per the datasheet of max8997.
> +
> +    For LDO's:
> +		LDOn {
> +			standard regulator bindings here
> +		};
> +
> +    For BUCK's:
> +		BUCKn {
> +			standard regulator bindings here
> +		};
> +
> +The bindings inside the regulator nodes use the standard regulator bindings
> +which are documented elsewhere.
> +
> +Example:
> +
> +	max8997_pmic@66 {
> +		compatible = "maxim,max8997-pmic";
> +		interrupt-parent = <&wakeup_eint>;
> +		reg = <0x66>;
> +		interrupts = <4 0>, <3 0>;
> +
> +		max8997,pmic-buck1-uses-gpio-dvs;
> +		max8997,pmic-buck2-uses-gpio-dvs;
> +		max8997,pmic-buck5-uses-gpio-dvs;
> +
> +		max8997,pmic-ignore-gpiodvs-side-effect;
> +		max8997,pmic-buck125-default-dvs-idx = <0>;
> +
> +		max8997,pmic-buck125-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */
> +						 <&gpx0 1 1 0 0>, /* SET2 */
> +						 <&gpx0 2 1 0 0>; /* SET3 */
> +
> +		max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
> +						 <1250000>, <1200000>,
> +						 <1150000>, <1100000>,
> +						 <1000000>, <950000>;
> +
> +		max8997,pmic-buck2-dvs-voltage = <1100000>, <1100000>,
> +				    		 <1100000>, <1100000>,
> +						 <1000000>, <1000000>,
> +						 <1000000>, <1000000>;
> +
> +		max8997,pmic-buck5-dvs-voltage = <1200000>, <1200000>,
> +						 <1200000>, <1200000>,
> +						 <1200000>, <1200000>,
> +						 <1200000>, <1200000>;
> +
> +		regulators {
> +			ldo1_reg: LDO1 {
> +				regulator-name = "VDD_ABB_3.3V";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <3300000>;
> +			};
> +
> +			ldo2_reg: LDO2 {
> +				regulator-name = "VDD_ALIVE_1.1V";
> +				regulator-min-microvolt = <1100000>;
> +				regulator-max-microvolt = <1100000>;
> +				regulator-always-on;
> +			};
> +
> +			buck1_reg: BUCK1 {
> +				regulator-name = "VDD_ARM_1.2V";
> +				regulator-min-microvolt = <950000>;
> +				regulator-max-microvolt = <1350000>;
> +				regulator-always-on;
> +				regulator-boot-on;
> +			};
> +		};
> +	};
> +

Good documentation

> diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
> index 20ecad3..13180be 100644
> --- a/drivers/mfd/max8997.c
> +++ b/drivers/mfd/max8997.c
> @@ -23,6 +23,7 @@
>  
>  #include <linux/slab.h>
>  #include <linux/i2c.h>
> +#include <linux/of_irq.h>
>  #include <linux/interrupt.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/module.h>
> @@ -123,6 +124,60 @@ int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
>  }
>  EXPORT_SYMBOL_GPL(max8997_update_reg);
>  
> +#ifdef CONFIG_OF
> +/*
> + * Only the common platform data elements for max8997 are parsed here from the
> + * device tree. Other sub-modules of max8997 such as pmic, rtc and others have
> + * to parse their own platform data elements from device tree.
> + *
> + * The max8997 platform data structure is instantiated here and the drivers for
> + * the sub-modules need not instantiate another instance while parsing their
> + * platform data.
> + */
> +static int max8997_i2c_parse_dt_pdata(struct device *dev,
> +					struct max8997_platform_data **pdata)
> +{
> +	struct max8997_platform_data *pd;
> +
> +	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
> +	if (!pd) {
> +		dev_err(dev, "could not allocate memory for pdata\n");
> +		return -ENOMEM;
> +	}
> +
> +	pd->ono = irq_of_parse_and_map(dev->of_node, 1);
> +
> +	/*
> +	 * ToDo: the 'wakeup' member in the platform data is more of a linux
> +	 * specfic information. Hence, there is no binding for that yet and
> +	 * not parsed here.
> +	 */
> +
> +	*pdata = pd;
> +	return 0;
> +}
> +#else
> +static int max8997_i2c_parse_dt_pdata(struct device *dev,
> +					struct max8997_platform_data **pdata)
> +{
> +	return 0;
> +}
> +#endif
> +
> +static struct of_device_id __devinitdata max8997_pmic_dt_match[];

Move the actual definition of this structure up to here so that a forward
declaration becomes unnecessary.

> +static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
> +						const struct i2c_device_id *id)
> +{
> +#ifdef CONFIG_OF
> +	if (i2c->dev.of_node) {
> +		const struct of_device_id *match;
> +		match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
> +		return (int)match->data;
> +	}
> +#endif
> +	return (int)id->driver_data;
> +}
> +
>  static int max8997_i2c_probe(struct i2c_client *i2c,
>  			    const struct i2c_device_id *id)
>  {
> @@ -137,9 +192,16 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
>  	i2c_set_clientdata(i2c, max8997);
>  	max8997->dev = &i2c->dev;
>  	max8997->i2c = i2c;
> -	max8997->type = id->driver_data;
> +	max8997->type = max8997_i2c_get_driver_data(i2c, id);
>  	max8997->irq = i2c->irq;
>  
> +	if (max8997->dev->of_node) {
> +		ret = max8997_i2c_parse_dt_pdata(max8997->dev, &pdata);
> +		if (ret)
> +			goto err;
> +		i2c->dev.platform_data = pdata;

This line is illegal.  Drivers must *not* change the value of dev->platform_data.
instead the valid pdata pointer needs to be stored in the max8997 private data
structure.

> +	}
> +

If you tweak the definition of max8997_i2c_parse_dt_pdata() then this block can
be simplified to:

	pdata = max8997_i2c_parse_dt_pdata(max8997->dev, &pdata);
	if (!pdata) 
		pdata = i2c->dev.platform_data,
	if (!pdata)
		goto err;


Otherwise, the patch looks pretty good.  (although seeing the decode function
has got me thinking that we need a much better way of decoding the dt data).

g.

>  
> @@ -429,11 +491,19 @@ const struct dev_pm_ops max8997_pm = {
>  	.restore = max8997_restore,
>  };
>  
> +#ifdef CONFIG_OF
> +static struct of_device_id __devinitdata max8997_pmic_dt_match[] = {
> +	{ .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 },
> +	{},
> +};
> +#endif
> +
>  static struct i2c_driver max8997_i2c_driver = {
>  	.driver = {
>  		   .name = "max8997",
>  		   .owner = THIS_MODULE,
>  		   .pm = &max8997_pm,
> +		   .of_match_table = of_match_ptr(max8997_pmic_dt_match),
>  	},
>  	.probe = max8997_i2c_probe,
>  	.remove = max8997_i2c_remove,
> diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
> index bb7cd9d..b31c4c9 100644
> --- a/drivers/regulator/max8997.c
> +++ b/drivers/regulator/max8997.c
> @@ -25,6 +25,7 @@
>  #include <linux/delay.h>
>  #include <linux/err.h>
>  #include <linux/gpio.h>
> +#include <linux/of_gpio.h>
>  #include <linux/slab.h>
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
> @@ -32,6 +33,7 @@
>  #include <linux/regulator/machine.h>
>  #include <linux/mfd/max8997.h>
>  #include <linux/mfd/max8997-private.h>
> +#include <linux/regulator/of_regulator.h>
>  
>  struct max8997_data {
>  	struct device *dev;
> @@ -958,6 +960,134 @@ static struct regulator_desc regulators[] = {
>  	},
>  };
>  
> +#ifdef CONFIG_OF
> +static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
> +			struct max8997_platform_data *pdata,
> +			struct device_node *pmic_np)
> +{
> +	int i, gpio;
> +
> +	for (i = 0; i < 3; i++) {
> +		gpio = of_get_named_gpio(pmic_np,
> +					"max8997,pmic-buck125-dvs-gpios", i);
> +		if (!gpio_is_valid(gpio)) {
> +			dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
> +			return -EINVAL;
> +		}
> +		pdata->buck125_gpios[i] = gpio;
> +	}
> +	return 0;
> +}
> +
> +static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
> +					struct max8997_platform_data *pdata)
> +{
> +	struct device_node *pmic_np, *regulators_np, *reg_np;
> +	struct max8997_regulator_data *rdata;
> +	unsigned int i, dvs_voltage_nr = 1, ret;
> +
> +	pmic_np = iodev->dev->of_node;
> +	if (!pmic_np) {
> +		dev_err(iodev->dev, "could not find pmic sub-node\n");
> +		return -ENODEV;
> +	}
> +
> +	regulators_np = of_find_node_by_name(pmic_np, "regulators");
> +	if (!regulators_np) {
> +		dev_err(iodev->dev, "could not find regulators sub-node\n");
> +		return -EINVAL;
> +	}
> +
> +	/* count the number of regulators to be supported in pmic */
> +	pdata->num_regulators = 0;
> +	for_each_child_of_node(regulators_np, reg_np)
> +		pdata->num_regulators++;
> +
> +	rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
> +				pdata->num_regulators, GFP_KERNEL);
> +	if (!rdata) {
> +		dev_err(iodev->dev, "could not allocate memory for "
> +						"regulator data\n");
> +		return -ENOMEM;
> +	}
> +
> +	pdata->regulators = rdata;
> +	for_each_child_of_node(regulators_np, reg_np) {
> +		for (i = 0; i < ARRAY_SIZE(regulators); i++)
> +			if (!of_node_cmp(reg_np->name, regulators[i].name))
> +				break;
> +		rdata->id = i;
> +		rdata->initdata = of_get_regulator_init_data(
> +						iodev->dev, reg_np);
> +		rdata->reg_node = reg_np;
> +		rdata++;
> +	}
> +
> +	if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
> +		pdata->buck1_gpiodvs = true;
> +
> +	if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL))
> +		pdata->buck2_gpiodvs = true;
> +
> +	if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL))
> +		pdata->buck5_gpiodvs = true;
> +
> +	if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
> +						pdata->buck5_gpiodvs) {
> +		ret = max8997_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
> +		if (ret)
> +			return -EINVAL;
> +
> +		if (of_property_read_u32(pmic_np,
> +				"max8997,pmic-buck125-default-dvs-idx",
> +				&pdata->buck125_default_idx)) {
> +			pdata->buck125_default_idx = 0;
> +		} else {
> +			if (pdata->buck125_default_idx >= 8) {
> +				pdata->buck125_default_idx = 0;
> +				dev_info(iodev->dev, "invalid value for "
> +				"default dvs index, using 0 instead\n");
> +			}
> +		}
> +
> +		if (of_get_property(pmic_np,
> +			"max8997,pmic-ignore-gpiodvs-side-effect", NULL))
> +			pdata->ignore_gpiodvs_side_effect = true;
> +
> +		dvs_voltage_nr = 8;
> +	}
> +
> +	if (of_property_read_u32_array(pmic_np,
> +				"max8997,pmic-buck1-dvs-voltage",
> +				pdata->buck1_voltage, dvs_voltage_nr)) {
> +		dev_err(iodev->dev, "buck1 voltages not specified\n");
> +		return -EINVAL;
> +	}
> +
> +	if (of_property_read_u32_array(pmic_np,
> +				"max8997,pmic-buck2-dvs-voltage",
> +				pdata->buck2_voltage, dvs_voltage_nr)) {
> +		dev_err(iodev->dev, "buck2 voltages not specified\n");
> +		return -EINVAL;
> +	}
> +
> +	if (of_property_read_u32_array(pmic_np,
> +				"max8997,pmic-buck5-dvs-voltage",
> +				pdata->buck5_voltage, dvs_voltage_nr)) {
> +		dev_err(iodev->dev, "buck5 voltages not specified\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +#else
> +static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
> +					struct max8997_platform_data *pdata)
> +{
> +	return 0;
> +}
> +#endif /* CONFIG_OF */
> +
>  static __devinit int max8997_pmic_probe(struct platform_device *pdev)
>  {
>  	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> @@ -968,6 +1098,12 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
>  	int i, ret, size;
>  	u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
>  
> +	if (iodev->dev->of_node) {
> +		ret = max8997_pmic_dt_parse_pdata(iodev, pdata);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	if (!pdata) {
>  		dev_err(pdev->dev.parent, "No platform init data supplied.\n");
>  		return -ENODEV;
> @@ -1146,7 +1282,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
>  			regulators[id].n_voltages = 16;
>  
>  		rdev[i] = regulator_register(&regulators[id], max8997->dev,
> -				pdata->regulators[i].initdata, max8997, NULL);
> +				pdata->regulators[i].initdata, max8997,
> +				pdata->regulators[i].reg_node);
>  		if (IS_ERR(rdev[i])) {
>  			ret = PTR_ERR(rdev[i]);
>  			dev_err(max8997->dev, "regulator init failed for %d\n",
> diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
> index 818486c..ba92375 100644
> --- a/include/linux/mfd/max8997.h
> +++ b/include/linux/mfd/max8997.h
> @@ -75,6 +75,7 @@ enum max8998_regulators {
>  struct max8997_regulator_data {
>  	int id;
>  	struct regulator_init_data *initdata;
> +	struct device_node *reg_node;
>  };
>  
>  enum max8997_muic_usb_type {
> -- 
> 1.6.6.rc2
> 

-- 
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies,Ltd.

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

* Re: [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts
  2012-03-13  3:28   ` Grant Likely
@ 2012-03-13  6:05     ` Thomas Abraham
  2012-03-13  8:15       ` Thomas Abraham
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Abraham @ 2012-03-13  6:05 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-kernel, k.lewandowsk, devicetree-discuss, rob.herring,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc

On 13 March 2012 08:58, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, 23 Feb 2012 18:08:07 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> Add irq domain support for max8997 interrupts. The reverse mapping method
>> used is linear mapping since the sub-drivers of max8997 such as regulator
>> and charger drivers can use the max8997 irq_domain to get the linux irq
>> number for max8997 interrupts. All uses of irq_base in platform data and
>> max8997 driver private data are removed.
>>
>> Cc: Grant Likely <grant.likely@secretlab.ca>
>> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  arch/arm/mach-exynos/mach-nuri.c    |    4 --
>>  arch/arm/mach-exynos/mach-origen.c  |    1 -
>>  drivers/mfd/max8997-irq.c           |   60 ++++++++++++++++++++--------------
>>  drivers/mfd/max8997.c               |    1 -
>>  include/linux/mfd/max8997-private.h |    4 ++-
>>  include/linux/mfd/max8997.h         |    1 -
>>  6 files changed, 38 insertions(+), 33 deletions(-)
>
> Nice patch.  Nice diffstat too.  Some comments below, but I'm happy with where
> this is at.
>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>

Thank you Grant for reviewing this patch.

>
>>
>> diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
>> index a6b9162..1e9ba12 100644
>> --- a/arch/arm/mach-exynos/mach-nuri.c
>> +++ b/arch/arm/mach-exynos/mach-nuri.c
>> @@ -1078,12 +1078,8 @@ static struct platform_device nuri_max8903_device = {
>>  static void __init nuri_power_init(void)
>>  {
>>       int gpio;
>> -     int irq_base = IRQ_GPIO_END + 1;
>>       int ta_en = 0;
>>
>> -     nuri_max8997_pdata.irq_base = irq_base;
>> -     irq_base += MAX8997_IRQ_NR;
>> -
>>       gpio = EXYNOS4_GPX0(7);
>>       gpio_request(gpio, "AP_PMIC_IRQ");
>>       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
>> diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
>> index 02c242e..328dadb 100644
>> --- a/arch/arm/mach-exynos/mach-origen.c
>> +++ b/arch/arm/mach-exynos/mach-origen.c
>> @@ -424,7 +424,6 @@ static struct max8997_platform_data __initdata origen_max8997_pdata = {
>>       .buck1_gpiodvs  = false,
>>       .buck2_gpiodvs  = false,
>>       .buck5_gpiodvs  = false,
>> -     .irq_base       = IRQ_GPIO_END + 1,
>>
>>       .ignore_gpiodvs_side_effect = true,
>>       .buck125_default_idx = 0x0,
>> diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c
>> index 09274cf..3d8c9d1 100644
>> --- a/drivers/mfd/max8997-irq.c
>> +++ b/drivers/mfd/max8997-irq.c
>> @@ -142,7 +142,8 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
>>  static const inline struct max8997_irq_data *
>>  irq_to_max8997_irq(struct max8997_dev *max8997, int irq)
>>  {
>> -     return &max8997_irqs[irq - max8997->irq_base];
>> +     struct irq_data *data = irq_get_irq_data(irq);
>> +     return &max8997_irqs[data->hwirq];
>
> Hahaha.  The max8997_irqs table is kind of overdone when the group and mask values
> can be arithmetically derived from the hwirq number..

Yes, I agree. Each group could have maximum of 8 interrupts. Then,
data->hwirq % 8 will be the group number and data->hwirq & 7 would be
the mask. The enum max8997_irq can then be adjusted to accommodate
unused irq numbers.

>
> This change is fine, but the driver could use some refactoring.  :-)

Ok.

>
>>  }
>>
>>  static void max8997_irq_mask(struct irq_data *data)
>> @@ -182,7 +183,7 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
>>       u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {};
>>       u8 irq_src;
>>       int ret;
>> -     int i;
>> +     int i, cur_irq;
>>
>>       ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src);
>>       if (ret < 0) {
>> @@ -269,8 +270,10 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
>>
>>       /* Report */
>>       for (i = 0; i < MAX8997_IRQ_NR; i++) {
>> -             if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask)
>> -                     handle_nested_irq(max8997->irq_base + i);
>> +             if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) {
>> +                     cur_irq = irq_find_mapping(max8997->irq_domain, i);
>> +                     handle_nested_irq(cur_irq);
>> +             }
>
> Well, if you're using the linear mapping, then only actually allocated irqs will
> have a mapping set up.  So the driver could simply do:
>
>        for (i = 0; i < MAX8997_IRQ_NR; i++) {
>                cur_irq = irq_find_mapping(max8997->irq_domain, i);
>                if (cur_irq)
>                        handle_nested_irq(cur_irq);
>        }

Thanks for the suggestion. I will include this change and repost this patch.

Regards,
Thomas.

[...]

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

* Re: [PATCH v3 2/2] regulator: add device tree support for max8997
  2012-03-13  3:43   ` Grant Likely
@ 2012-03-13  6:44     ` Thomas Abraham
  2012-03-13 18:18       ` Grant Likely
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Abraham @ 2012-03-13  6:44 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-kernel, k.lewandowsk, devicetree-discuss, rob.herring,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc, Rajendra Nayak

On 13 March 2012 09:13, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, 23 Feb 2012 18:08:08 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> Add device tree based discovery support for max8997.
>>
>> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Cc: Rajendra Nayak <rnayak@ti.com>
>> Cc: Rob Herring <rob.herring@calxeda.com>
>> Cc: Grant Likely <grant.likely@secretlab.ca>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  .../devicetree/bindings/regulator/max8997-pmic.txt |  134 +++++++++++++++++++
>>  drivers/mfd/max8997.c                              |   72 ++++++++++-
>>  drivers/regulator/max8997.c                        |  139 +++++++++++++++++++-
>>  include/linux/mfd/max8997.h                        |    1 +
>>  4 files changed, 344 insertions(+), 2 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/regulator/max8997-pmic.txt
>>

[...]

>> diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
>> index 20ecad3..13180be 100644
>> --- a/drivers/mfd/max8997.c
>> +++ b/drivers/mfd/max8997.c
>> @@ -23,6 +23,7 @@
>>
>>  #include <linux/slab.h>
>>  #include <linux/i2c.h>
>> +#include <linux/of_irq.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/pm_runtime.h>
>>  #include <linux/module.h>
>> @@ -123,6 +124,60 @@ int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
>>  }
>>  EXPORT_SYMBOL_GPL(max8997_update_reg);
>>
>> +#ifdef CONFIG_OF
>> +/*
>> + * Only the common platform data elements for max8997 are parsed here from the
>> + * device tree. Other sub-modules of max8997 such as pmic, rtc and others have
>> + * to parse their own platform data elements from device tree.
>> + *
>> + * The max8997 platform data structure is instantiated here and the drivers for
>> + * the sub-modules need not instantiate another instance while parsing their
>> + * platform data.
>> + */
>> +static int max8997_i2c_parse_dt_pdata(struct device *dev,
>> +                                     struct max8997_platform_data **pdata)
>> +{
>> +     struct max8997_platform_data *pd;
>> +
>> +     pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
>> +     if (!pd) {
>> +             dev_err(dev, "could not allocate memory for pdata\n");
>> +             return -ENOMEM;
>> +     }
>> +
>> +     pd->ono = irq_of_parse_and_map(dev->of_node, 1);
>> +
>> +     /*
>> +      * ToDo: the 'wakeup' member in the platform data is more of a linux
>> +      * specfic information. Hence, there is no binding for that yet and
>> +      * not parsed here.
>> +      */
>> +
>> +     *pdata = pd;
>> +     return 0;
>> +}
>> +#else
>> +static int max8997_i2c_parse_dt_pdata(struct device *dev,
>> +                                     struct max8997_platform_data **pdata)
>> +{
>> +     return 0;
>> +}
>> +#endif
>> +
>> +static struct of_device_id __devinitdata max8997_pmic_dt_match[];
>
> Move the actual definition of this structure up to here so that a forward
> declaration becomes unnecessary.
>

Ok.

>> +static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
>> +                                             const struct i2c_device_id *id)
>> +{
>> +#ifdef CONFIG_OF
>> +     if (i2c->dev.of_node) {
>> +             const struct of_device_id *match;
>> +             match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
>> +             return (int)match->data;
>> +     }
>> +#endif
>> +     return (int)id->driver_data;
>> +}
>> +
>>  static int max8997_i2c_probe(struct i2c_client *i2c,
>>                           const struct i2c_device_id *id)
>>  {
>> @@ -137,9 +192,16 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
>>       i2c_set_clientdata(i2c, max8997);
>>       max8997->dev = &i2c->dev;
>>       max8997->i2c = i2c;
>> -     max8997->type = id->driver_data;
>> +     max8997->type = max8997_i2c_get_driver_data(i2c, id);
>>       max8997->irq = i2c->irq;
>>
>> +     if (max8997->dev->of_node) {
>> +             ret = max8997_i2c_parse_dt_pdata(max8997->dev, &pdata);
>> +             if (ret)
>> +                     goto err;
>> +             i2c->dev.platform_data = pdata;
>
> This line is illegal.  Drivers must *not* change the value of dev->platform_data.
> instead the valid pdata pointer needs to be stored in the max8997 private data
> structure.

The intention here was to let the max8897 driver's mfd portion create
an 'common' instance of max8897 platform data and allow the max8997
sub-drivers such as the pmic driver and charger driver use that
'common' instance to populate their respective platform data portions
from dt. But, assigning that allocated pdata pointer to
i2c->dev.platform_data was not correct, I agree.

Instead, a new pointer to 'struct max8997_platform_data' will be added
to 'struct max8997_dev', assign the pdata in the mfd driver to this
new member and let the sub-drivers use the pdata pointer in 'struct
max8997_dev'. I will do this change and repost this patch.

>
>> +     }
>> +
>
> If you tweak the definition of max8997_i2c_parse_dt_pdata() then this block can
> be simplified to:
>
>        pdata = max8997_i2c_parse_dt_pdata(max8997->dev, &pdata);
>        if (!pdata)
>                pdata = i2c->dev.platform_data,
>        if (!pdata)
>                goto err;
>
>
> Otherwise, the patch looks pretty good.  (although seeing the decode function
> has got me thinking that we need a much better way of decoding the dt data).

The parsing function looks huge since there is lot of data to pick up
from the dt node.

Thanks for your comments.

Regards,
Thomas.

[...]

>
> g.

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

* Re: [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts
  2012-03-13  6:05     ` Thomas Abraham
@ 2012-03-13  8:15       ` Thomas Abraham
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Abraham @ 2012-03-13  8:15 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-kernel, k.lewandowsk, devicetree-discuss, rob.herring,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc

On 13 March 2012 11:35, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 13 March 2012 08:58, Grant Likely <grant.likely@secretlab.ca> wrote:
>> On Thu, 23 Feb 2012 18:08:07 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>>> Add irq domain support for max8997 interrupts. The reverse mapping method
>>> used is linear mapping since the sub-drivers of max8997 such as regulator
>>> and charger drivers can use the max8997 irq_domain to get the linux irq
>>> number for max8997 interrupts. All uses of irq_base in platform data and
>>> max8997 driver private data are removed.
>>>
>>> Cc: Grant Likely <grant.likely@secretlab.ca>
>>> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
>>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>>> ---
>>>  arch/arm/mach-exynos/mach-nuri.c    |    4 --
>>>  arch/arm/mach-exynos/mach-origen.c  |    1 -
>>>  drivers/mfd/max8997-irq.c           |   60 ++++++++++++++++++++--------------
>>>  drivers/mfd/max8997.c               |    1 -
>>>  include/linux/mfd/max8997-private.h |    4 ++-
>>>  include/linux/mfd/max8997.h         |    1 -
>>>  6 files changed, 38 insertions(+), 33 deletions(-)

[...]

>>
>> Hahaha.  The max8997_irqs table is kind of overdone when the group and mask values
>> can be arithmetically derived from the hwirq number..
>
> Yes, I agree. Each group could have maximum of 8 interrupts. Then,
> data->hwirq % 8 will be the group number and data->hwirq & 7 would be

Typo here. group number = data->hwirq >> 3 and mask = data->hwirq & 7.

Thanks,
Thomas.

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

* Re: [PATCH v3 2/2] regulator: add device tree support for max8997
  2012-03-13  6:44     ` Thomas Abraham
@ 2012-03-13 18:18       ` Grant Likely
  0 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2012-03-13 18:18 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: linux-kernel, k.lewandowsk, devicetree-discuss, rob.herring,
	kgene.kim, broonie, myungjoo.ham, kyungmin.park, dg77.kim,
	linux-arm-kernel, linux-samsung-soc, Rajendra Nayak

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 625 bytes --]

On Tue, 13 Mar 2012 12:14:42 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> On 13 March 2012 09:13, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On Thu, 23 Feb 2012 18:08:08 +0530, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> > Otherwise, the patch looks pretty good.  (although seeing the decode function
> > has got me thinking that we need a much better way of decoding the dt data).
> 
> The parsing function looks huge since there is lot of data to pick up
> from the dt node.

Oh, I understand that you have to do it this way; I just think the core code
should make it a lot easier.  :-)

g.

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

end of thread, other threads:[~2012-03-13 18:18 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-23 12:38 [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham
2012-02-23 12:38 ` [PATCH v3 1/2] mfd: add irq domain support for max8997 interrupts Thomas Abraham
2012-03-13  3:28   ` Grant Likely
2012-03-13  6:05     ` Thomas Abraham
2012-03-13  8:15       ` Thomas Abraham
2012-02-23 12:38 ` [PATCH v3 2/2] regulator: add device tree support for max8997 Thomas Abraham
2012-03-13  3:43   ` Grant Likely
2012-03-13  6:44     ` Thomas Abraham
2012-03-13 18:18       ` Grant Likely
2012-03-12 21:10 ` [PATCH v3 0/2] regulator: add irq domain and device tree support for MAX8997 Thomas Abraham

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).