All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-25 19:03 ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
a Real-Time-Clock (RTC) and a I2C interface to program the individual
regulators, clocks and the RTC.

This fourth version of the patch-set addresses several issues pointed
out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
changes are added on each patch change log.

This series are based on drivers added by Simon Glass to the Chrome OS
kernel and adds support for the Maxim 77802 Power Management IC, their
regulators, clocks, RTC and I2C interface.

NOTE: This version of the series model the real power scheme for Maxim
77802 regulators instead of a simplistic model like in older versions.
So these changes depend on patch:

"[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
https://patchwork.kernel.org/patch/4411351/

which adds tps65090 support to Peach boards since regulators from this
PMIC supply power to a set of MAX77802 regulators.

The patch-set has been tested on both Daisy/Snow (max77686) and Peach
pit (max77802) Chromebooks and it's composed of the following patches:

Doug Anderson (1):
  mfd: max77686: Allow the max77686 rtc to wakeup the system

Javier Martinez Canillas (13):
  mfd: max77686: Convert to use regmap_irq
  clk: max77686: Add DT include for MAX77686 PMIC clock
  clk: max77686: Improve Maxim 77686 PMIC clocks binding
  clk: Add generic driver for Maxim PMIC clocks
  clk: max77686: Convert to the generic max clock driver
  mfd: Add driver for Maxim 77802 Power Management IC
  mfd: max77802: Add DT binding documentation
  regmap: Add regmap_reg_copy function
  regulator: Add driver for Maxim 77802 PMIC regulators
  clk: Add driver for Maxim 77802 PMIC clocks
  clk: max77802: Add DT binding documentation
  rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
  ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi

 .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
 .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
 Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
 arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
 arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
 drivers/base/regmap/regmap.c                       |  34 +
 drivers/clk/Kconfig                                |  11 +
 drivers/clk/Makefile                               |   2 +
 drivers/clk/clk-max-gen.c                          | 195 ++++++
 drivers/clk/clk-max-gen.h                          |  32 +
 drivers/clk/clk-max77686.c                         | 183 +-----
 drivers/clk/clk-max77802.c                         |  99 +++
 drivers/mfd/Kconfig                                |  15 +
 drivers/mfd/Makefile                               |   3 +-
 drivers/mfd/max77686-irq.c                         | 319 ----------
 drivers/mfd/max77686.c                             |  97 ++-
 drivers/mfd/max77802.c                             | 366 +++++++++++
 drivers/regulator/Kconfig                          |   9 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
 drivers/rtc/Kconfig                                |  10 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-max77686.c                         |  55 +-
 drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
 include/dt-bindings/clock/maxim,max77686.h         |  23 +
 include/dt-bindings/clock/maxim,max77802.h         |  22 +
 include/linux/mfd/max77686-private.h               |  28 +-
 include/linux/mfd/max77686.h                       |   2 -
 include/linux/mfd/max77802-private.h               | 307 +++++++++
 include/linux/mfd/max77802.h                       | 121 ++++
 include/linux/regmap.h                             |   9 +
 31 files changed, 3583 insertions(+), 532 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
 create mode 100644 drivers/clk/clk-max-gen.c
 create mode 100644 drivers/clk/clk-max-gen.h
 create mode 100644 drivers/clk/clk-max77802.c
 delete mode 100644 drivers/mfd/max77686-irq.c
 create mode 100644 drivers/mfd/max77802.c
 create mode 100644 drivers/regulator/max77802.c
 create mode 100644 drivers/rtc/rtc-max77802.c
 create mode 100644 include/dt-bindings/clock/maxim,max77686.h
 create mode 100644 include/dt-bindings/clock/maxim,max77802.h
 create mode 100644 include/linux/mfd/max77802-private.h
 create mode 100644 include/linux/mfd/max77802.h

-- 
2.0.0.rc2

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

* [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-25 19:03 ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
a Real-Time-Clock (RTC) and a I2C interface to program the individual
regulators, clocks and the RTC.

This fourth version of the patch-set addresses several issues pointed
out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
changes are added on each patch change log.

This series are based on drivers added by Simon Glass to the Chrome OS
kernel and adds support for the Maxim 77802 Power Management IC, their
regulators, clocks, RTC and I2C interface.

NOTE: This version of the series model the real power scheme for Maxim
77802 regulators instead of a simplistic model like in older versions.
So these changes depend on patch:

"[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
https://patchwork.kernel.org/patch/4411351/

which adds tps65090 support to Peach boards since regulators from this
PMIC supply power to a set of MAX77802 regulators.

The patch-set has been tested on both Daisy/Snow (max77686) and Peach
pit (max77802) Chromebooks and it's composed of the following patches:

Doug Anderson (1):
  mfd: max77686: Allow the max77686 rtc to wakeup the system

Javier Martinez Canillas (13):
  mfd: max77686: Convert to use regmap_irq
  clk: max77686: Add DT include for MAX77686 PMIC clock
  clk: max77686: Improve Maxim 77686 PMIC clocks binding
  clk: Add generic driver for Maxim PMIC clocks
  clk: max77686: Convert to the generic max clock driver
  mfd: Add driver for Maxim 77802 Power Management IC
  mfd: max77802: Add DT binding documentation
  regmap: Add regmap_reg_copy function
  regulator: Add driver for Maxim 77802 PMIC regulators
  clk: Add driver for Maxim 77802 PMIC clocks
  clk: max77802: Add DT binding documentation
  rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
  ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi

 .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
 .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
 Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
 arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
 arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
 drivers/base/regmap/regmap.c                       |  34 +
 drivers/clk/Kconfig                                |  11 +
 drivers/clk/Makefile                               |   2 +
 drivers/clk/clk-max-gen.c                          | 195 ++++++
 drivers/clk/clk-max-gen.h                          |  32 +
 drivers/clk/clk-max77686.c                         | 183 +-----
 drivers/clk/clk-max77802.c                         |  99 +++
 drivers/mfd/Kconfig                                |  15 +
 drivers/mfd/Makefile                               |   3 +-
 drivers/mfd/max77686-irq.c                         | 319 ----------
 drivers/mfd/max77686.c                             |  97 ++-
 drivers/mfd/max77802.c                             | 366 +++++++++++
 drivers/regulator/Kconfig                          |   9 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
 drivers/rtc/Kconfig                                |  10 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-max77686.c                         |  55 +-
 drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
 include/dt-bindings/clock/maxim,max77686.h         |  23 +
 include/dt-bindings/clock/maxim,max77802.h         |  22 +
 include/linux/mfd/max77686-private.h               |  28 +-
 include/linux/mfd/max77686.h                       |   2 -
 include/linux/mfd/max77802-private.h               | 307 +++++++++
 include/linux/mfd/max77802.h                       | 121 ++++
 include/linux/regmap.h                             |   9 +
 31 files changed, 3583 insertions(+), 532 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
 create mode 100644 drivers/clk/clk-max-gen.c
 create mode 100644 drivers/clk/clk-max-gen.h
 create mode 100644 drivers/clk/clk-max77802.c
 delete mode 100644 drivers/mfd/max77686-irq.c
 create mode 100644 drivers/mfd/max77802.c
 create mode 100644 drivers/regulator/max77802.c
 create mode 100644 drivers/rtc/rtc-max77802.c
 create mode 100644 include/dt-bindings/clock/maxim,max77686.h
 create mode 100644 include/dt-bindings/clock/maxim,max77802.h
 create mode 100644 include/linux/mfd/max77802-private.h
 create mode 100644 include/linux/mfd/max77802.h

-- 
2.0.0.rc2

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

* [PATCH v4 01/14] mfd: max77686: Convert to use regmap_irq
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

By using the generic IRQ support in the Register map API, it
is possible to get rid max77686-irq.c and simplify the code.

Suggested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Acked-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
---

Changes since v3: None

Changes since v2:
 - Cleanup regmap irqchips on i2c_driver .remove function.
   Suggested by Doug Anderson.
 - Remove unused MAX77686_IRQ_NR enum. Suggested by Doug Anderson.

 drivers/mfd/Kconfig                  |   1 +
 drivers/mfd/Makefile                 |   2 +-
 drivers/mfd/max77686-irq.c           | 319 -----------------------------------
 drivers/mfd/max77686.c               |  97 ++++++++++-
 drivers/rtc/rtc-max77686.c           |  27 +--
 include/linux/mfd/max77686-private.h |  28 ++-
 include/linux/mfd/max77686.h         |   2 -
 7 files changed, 123 insertions(+), 353 deletions(-)
 delete mode 100644 drivers/mfd/max77686-irq.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index af0e83f..b53cc5e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -383,6 +383,7 @@ config MFD_MAX77686
 	depends on I2C=y
 	select MFD_CORE
 	select REGMAP_I2C
+	select REGMAP_IRQ
 	select IRQ_DOMAIN
 	help
 	  Say yes here to add support for Maxim Semiconductor MAX77686.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4e2bc25..f001487 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -115,7 +115,7 @@ da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
 obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
-obj-$(CONFIG_MFD_MAX77686)	+= max77686.o max77686-irq.o
+obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
diff --git a/drivers/mfd/max77686-irq.c b/drivers/mfd/max77686-irq.c
deleted file mode 100644
index cdc3280..0000000
--- a/drivers/mfd/max77686-irq.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * max77686-irq.c - Interrupt controller support for MAX77686
- *
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- * Chiwoong Byun <woong.byun@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This driver is based on max8997-irq.c
- */
-
-#include <linux/err.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mfd/max77686.h>
-#include <linux/mfd/max77686-private.h>
-#include <linux/irqdomain.h>
-#include <linux/regmap.h>
-
-enum {
-	MAX77686_DEBUG_IRQ_INFO = 1 << 0,
-	MAX77686_DEBUG_IRQ_MASK = 1 << 1,
-	MAX77686_DEBUG_IRQ_INT = 1 << 2,
-};
-
-static int debug_mask = 0;
-module_param(debug_mask, int, 0);
-MODULE_PARM_DESC(debug_mask, "Set debug_mask : 0x0=off 0x1=IRQ_INFO  0x2=IRQ_MASK 0x4=IRQ_INI)");
-
-static const u8 max77686_mask_reg[] = {
-	[PMIC_INT1] = MAX77686_REG_INT1MSK,
-	[PMIC_INT2] = MAX77686_REG_INT2MSK,
-	[RTC_INT] = MAX77686_RTC_INTM,
-};
-
-static struct regmap *max77686_get_regmap(struct max77686_dev *max77686,
-				enum max77686_irq_source src)
-{
-	switch (src) {
-	case PMIC_INT1 ... PMIC_INT2:
-		return max77686->regmap;
-	case RTC_INT:
-		return max77686->rtc_regmap;
-	default:
-		return ERR_PTR(-EINVAL);
-	}
-}
-
-struct max77686_irq_data {
-	int mask;
-	enum max77686_irq_source group;
-};
-
-#define DECLARE_IRQ(idx, _group, _mask)		\
-	[(idx)] = { .group = (_group), .mask = (_mask) }
-static const struct max77686_irq_data max77686_irqs[] = {
-	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONF,	PMIC_INT1, 1 << 0),
-	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONR,	PMIC_INT1, 1 << 1),
-	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBF,	PMIC_INT1, 1 << 2),
-	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBR,	PMIC_INT1, 1 << 3),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBF,	PMIC_INT1, 1 << 4),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBR,	PMIC_INT1, 1 << 5),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ONKEY1S,	PMIC_INT1, 1 << 6),
-	DECLARE_IRQ(MAX77686_PMICIRQ_MRSTB,		PMIC_INT1, 1 << 7),
-	DECLARE_IRQ(MAX77686_PMICIRQ_140C,		PMIC_INT2, 1 << 0),
-	DECLARE_IRQ(MAX77686_PMICIRQ_120C,		PMIC_INT2, 1 << 1),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTC60S,		RTC_INT, 1 << 0),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA1,		RTC_INT, 1 << 1),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA2,		RTC_INT, 1 << 2),
-	DECLARE_IRQ(MAX77686_RTCIRQ_SMPL,		RTC_INT, 1 << 3),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTC1S,		RTC_INT, 1 << 4),
-	DECLARE_IRQ(MAX77686_RTCIRQ_WTSR,		RTC_INT, 1 << 5),
-};
-
-static void max77686_irq_lock(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s\n", __func__);
-
-	mutex_lock(&max77686->irqlock);
-}
-
-static void max77686_irq_sync_unlock(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	int i;
-
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
-		u8 mask_reg = max77686_mask_reg[i];
-		struct regmap *map = max77686_get_regmap(max77686, i);
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-			pr_debug("%s: mask_reg[%d]=0x%x, cur=0x%x\n",
-			__func__, i, mask_reg, max77686->irq_masks_cur[i]);
-
-		if (mask_reg == MAX77686_REG_INVALID ||
-				IS_ERR_OR_NULL(map))
-			continue;
-
-		max77686->irq_masks_cache[i] = max77686->irq_masks_cur[i];
-
-		regmap_write(map, max77686_mask_reg[i],
-				max77686->irq_masks_cur[i]);
-	}
-
-	mutex_unlock(&max77686->irqlock);
-}
-
-static const inline struct max77686_irq_data *to_max77686_irq(int irq)
-{
-	struct irq_data *data = irq_get_irq_data(irq);
-	return &max77686_irqs[data->hwirq];
-}
-
-static void max77686_irq_mask(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
-
-	max77686->irq_masks_cur[irq_data->group] |= irq_data->mask;
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s: group=%d, cur=0x%x\n",
-			__func__, irq_data->group,
-			max77686->irq_masks_cur[irq_data->group]);
-}
-
-static void max77686_irq_unmask(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
-
-	max77686->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s: group=%d, cur=0x%x\n",
-			__func__, irq_data->group,
-			max77686->irq_masks_cur[irq_data->group]);
-}
-
-static struct irq_chip max77686_irq_chip = {
-	.name			= "max77686",
-	.irq_bus_lock		= max77686_irq_lock,
-	.irq_bus_sync_unlock	= max77686_irq_sync_unlock,
-	.irq_mask		= max77686_irq_mask,
-	.irq_unmask		= max77686_irq_unmask,
-};
-
-static irqreturn_t max77686_irq_thread(int irq, void *data)
-{
-	struct max77686_dev *max77686 = data;
-	unsigned int irq_reg[MAX77686_IRQ_GROUP_NR] = {};
-	unsigned int irq_src;
-	int ret;
-	int i, cur_irq;
-
-	ret = regmap_read(max77686->regmap,  MAX77686_REG_INTSRC, &irq_src);
-	if (ret < 0) {
-		dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-				ret);
-		return IRQ_NONE;
-	}
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-		pr_info("%s: irq_src=0x%x\n", __func__, irq_src);
-
-	if (irq_src == MAX77686_IRQSRC_PMIC) {
-		ret = regmap_bulk_read(max77686->regmap,
-					 MAX77686_REG_INT1, irq_reg, 2);
-		if (ret < 0) {
-			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-					ret);
-			return IRQ_NONE;
-		}
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-			pr_info("%s: int1=0x%x, int2=0x%x\n", __func__,
-				 irq_reg[PMIC_INT1], irq_reg[PMIC_INT2]);
-	}
-
-	if (irq_src & MAX77686_IRQSRC_RTC) {
-		ret = regmap_read(max77686->rtc_regmap,
-					MAX77686_RTC_INT, &irq_reg[RTC_INT]);
-		if (ret < 0) {
-			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-					ret);
-			return IRQ_NONE;
-		}
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-			pr_info("%s: rtc int=0x%x\n", __func__,
-							 irq_reg[RTC_INT]);
-
-	}
-
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++)
-		irq_reg[i] &= ~max77686->irq_masks_cur[i];
-
-	for (i = 0; i < MAX77686_IRQ_NR; i++) {
-		if (irq_reg[max77686_irqs[i].group] & max77686_irqs[i].mask) {
-			cur_irq = irq_find_mapping(max77686->irq_domain, i);
-			if (cur_irq)
-				handle_nested_irq(cur_irq);
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int max77686_irq_domain_map(struct irq_domain *d, unsigned int irq,
-					irq_hw_number_t hw)
-{
-	struct max77686_dev *max77686 = d->host_data;
-
-	irq_set_chip_data(irq, max77686);
-	irq_set_chip_and_handler(irq, &max77686_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 max77686_irq_domain_ops = {
-	.map = max77686_irq_domain_map,
-};
-
-int max77686_irq_init(struct max77686_dev *max77686)
-{
-	struct irq_domain *domain;
-	int i;
-	int ret;
-	int val;
-	struct regmap *map;
-
-	mutex_init(&max77686->irqlock);
-
-	if (max77686->irq_gpio && !max77686->irq) {
-		max77686->irq = gpio_to_irq(max77686->irq_gpio);
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT) {
-			ret = gpio_request(max77686->irq_gpio, "pmic_irq");
-			if (ret < 0) {
-				dev_err(max77686->dev,
-					"Failed to request gpio %d with ret:"
-					"%d\n",	max77686->irq_gpio, ret);
-				return IRQ_NONE;
-			}
-
-			gpio_direction_input(max77686->irq_gpio);
-			val = gpio_get_value(max77686->irq_gpio);
-			gpio_free(max77686->irq_gpio);
-			pr_info("%s: gpio_irq=%x\n", __func__, val);
-		}
-	}
-
-	if (!max77686->irq) {
-		dev_err(max77686->dev, "irq is not specified\n");
-		return -ENODEV;
-	}
-
-	/* Mask individual interrupt sources */
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
-		max77686->irq_masks_cur[i] = 0xff;
-		max77686->irq_masks_cache[i] = 0xff;
-		map = max77686_get_regmap(max77686, i);
-
-		if (IS_ERR_OR_NULL(map))
-			continue;
-		if (max77686_mask_reg[i] == MAX77686_REG_INVALID)
-			continue;
-
-		regmap_write(map, max77686_mask_reg[i], 0xff);
-	}
-	domain = irq_domain_add_linear(NULL, MAX77686_IRQ_NR,
-					&max77686_irq_domain_ops, max77686);
-	if (!domain) {
-		dev_err(max77686->dev, "could not create irq domain\n");
-		return -ENODEV;
-	}
-	max77686->irq_domain = domain;
-
-	ret = request_threaded_irq(max77686->irq, NULL, max77686_irq_thread,
-				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-				   "max77686-irq", max77686);
-
-	if (ret)
-		dev_err(max77686->dev, "Failed to request IRQ %d: %d\n",
-			max77686->irq, ret);
-
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_INFO)
-		pr_info("%s-\n", __func__);
-
-	return 0;
-}
-
-void max77686_irq_exit(struct max77686_dev *max77686)
-{
-	if (max77686->irq)
-		free_irq(max77686->irq, max77686);
-}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index ce869ac..3cb41d0 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -25,6 +25,8 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/mfd/core.h>
@@ -46,6 +48,54 @@ static struct regmap_config max77686_regmap_config = {
 	.val_bits = 8,
 };
 
+static struct regmap_config max77686_rtc_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static const struct regmap_irq max77686_irqs[] = {
+	/* INT1 interrupts */
+	{ .reg_offset = 0, .mask = MAX77686_INT1_PWRONF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_PWRONR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_JIGONBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_JIGONBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ACOKBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ACOKBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ONKEY1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_MRSTB_MSK, },
+	/* INT2 interrupts */
+	{ .reg_offset = 1, .mask = MAX77686_INT2_140C_MSK, },
+	{ .reg_offset = 1, .mask = MAX77686_INT2_120C_MSK, },
+};
+
+static const struct regmap_irq_chip max77686_irq_chip = {
+	.name			= "max77686-pmic",
+	.status_base		= MAX77686_REG_INT1,
+	.mask_base		= MAX77686_REG_INT1MSK,
+	.num_regs		= 2,
+	.irqs			= max77686_irqs,
+	.num_irqs		= ARRAY_SIZE(max77686_irqs),
+};
+
+static const struct regmap_irq max77686_rtc_irqs[] = {
+	/* RTC interrupts */
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, },
+};
+
+static const struct regmap_irq_chip max77686_rtc_irq_chip = {
+	.name			= "max77686-rtc",
+	.status_base		= MAX77686_RTC_INT,
+	.mask_base		= MAX77686_RTC_INTM,
+	.num_regs		= 1,
+	.irqs			= max77686_rtc_irqs,
+	.num_irqs		= ARRAY_SIZE(max77686_rtc_irqs),
+};
+
 #ifdef CONFIG_OF
 static const struct of_device_id max77686_pmic_dt_match[] = {
 	{.compatible = "maxim,max77686", .data = NULL},
@@ -101,7 +151,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 	max77686->type = id->driver_data;
 
 	max77686->wakeup = pdata->wakeup;
-	max77686->irq_gpio = pdata->irq_gpio;
 	max77686->irq = i2c->irq;
 
 	max77686->regmap = devm_regmap_init_i2c(i2c, &max77686_regmap_config);
@@ -117,8 +166,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 		dev_err(max77686->dev,
 			"device not found on this channel (this is not an error)\n");
 		return -ENODEV;
-	} else
-		dev_info(max77686->dev, "device found\n");
+	}
 
 	max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
 	if (!max77686->rtc) {
@@ -127,15 +175,48 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 	}
 	i2c_set_clientdata(max77686->rtc, max77686);
 
-	max77686_irq_init(max77686);
+	max77686->rtc_regmap = devm_regmap_init_i2c(max77686->rtc,
+						    &max77686_rtc_regmap_config);
+	if (IS_ERR(max77686->rtc_regmap)) {
+		ret = PTR_ERR(max77686->rtc_regmap);
+		dev_err(max77686->dev, "failed to allocate RTC regmap: %d\n",
+			ret);
+		goto err_unregister_i2c;
+	}
+
+	ret = regmap_add_irq_chip(max77686->regmap, max77686->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77686_irq_chip,
+				  &max77686->irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
+		goto err_unregister_i2c;
+	}
+	ret = regmap_add_irq_chip(max77686->rtc_regmap, max77686->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77686_rtc_irq_chip,
+				  &max77686->rtc_irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
+		goto err_del_irqc;
+	}
 
 	ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
 			      ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
 	if (ret < 0) {
-		mfd_remove_devices(max77686->dev);
-		i2c_unregister_device(max77686->rtc);
+		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+		goto err_del_rtc_irqc;
 	}
 
+	return 0;
+
+err_del_rtc_irqc:
+	regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
+err_del_irqc:
+	regmap_del_irq_chip(max77686->irq, max77686->irq_data);
+err_unregister_i2c:
+	i2c_unregister_device(max77686->rtc);
+
 	return ret;
 }
 
@@ -144,6 +225,10 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
 	struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
 
 	mfd_remove_devices(max77686->dev);
+
+	regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
+	regmap_del_irq_chip(max77686->irq, max77686->irq_data);
+
 	i2c_unregister_device(max77686->rtc);
 
 	return 0;
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 9efe118..d20a7f0 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -492,16 +492,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
 	return ret;
 }
 
-static struct regmap_config max77686_rtc_regmap_config = {
-	.reg_bits = 8,
-	.val_bits = 8,
-};
-
 static int max77686_rtc_probe(struct platform_device *pdev)
 {
 	struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
 	struct max77686_rtc_info *info;
-	int ret, virq;
+	int ret;
 
 	dev_info(&pdev->dev, "%s\n", __func__);
 
@@ -514,14 +509,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
 	info->dev = &pdev->dev;
 	info->max77686 = max77686;
 	info->rtc = max77686->rtc;
-	info->max77686->rtc_regmap = devm_regmap_init_i2c(info->max77686->rtc,
-					 &max77686_rtc_regmap_config);
-	if (IS_ERR(info->max77686->rtc_regmap)) {
-		ret = PTR_ERR(info->max77686->rtc_regmap);
-		dev_err(info->max77686->dev, "Failed to allocate register map: %d\n",
-				ret);
-		return ret;
-	}
+
 	platform_set_drvdata(pdev, info);
 
 	ret = max77686_rtc_init_reg(info);
@@ -550,15 +538,16 @@ static int max77686_rtc_probe(struct platform_device *pdev)
 			ret = -EINVAL;
 		goto err_rtc;
 	}
-	virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1);
-	if (!virq) {
+
+	info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
+					 MAX77686_RTCIRQ_RTCA1);
+	if (!info->virq) {
 		ret = -ENXIO;
 		goto err_rtc;
 	}
-	info->virq = virq;
 
-	ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
-				max77686_rtc_alarm_irq, 0, "rtc-alarm0", info);
+	ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
+				max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
 	if (ret < 0)
 		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
 			info->virq, ret);
diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h
index 8c75a9c..d86b547 100644
--- a/include/linux/mfd/max77686-private.h
+++ b/include/linux/mfd/max77686-private.h
@@ -205,16 +205,33 @@ enum max77686_irq {
 	MAX77686_PMICIRQ_140C,
 	MAX77686_PMICIRQ_120C,
 
-	MAX77686_RTCIRQ_RTC60S,
+	MAX77686_RTCIRQ_RTC60S = 0,
 	MAX77686_RTCIRQ_RTCA1,
 	MAX77686_RTCIRQ_RTCA2,
 	MAX77686_RTCIRQ_SMPL,
 	MAX77686_RTCIRQ_RTC1S,
 	MAX77686_RTCIRQ_WTSR,
-
-	MAX77686_IRQ_NR,
 };
 
+#define MAX77686_INT1_PWRONF_MSK	BIT(0)
+#define MAX77686_INT1_PWRONR_MSK	BIT(1)
+#define MAX77686_INT1_JIGONBF_MSK	BIT(2)
+#define MAX77686_INT1_JIGONBR_MSK	BIT(3)
+#define MAX77686_INT1_ACOKBF_MSK	BIT(4)
+#define MAX77686_INT1_ACOKBR_MSK	BIT(5)
+#define MAX77686_INT1_ONKEY1S_MSK	BIT(6)
+#define MAX77686_INT1_MRSTB_MSK		BIT(7)
+
+#define MAX77686_INT2_140C_MSK		BIT(0)
+#define MAX77686_INT2_120C_MSK		BIT(1)
+
+#define MAX77686_RTCINT_RTC60S_MSK	BIT(0)
+#define MAX77686_RTCINT_RTCA1_MSK	BIT(1)
+#define MAX77686_RTCINT_RTCA2_MSK	BIT(2)
+#define MAX77686_RTCINT_SMPL_MSK	BIT(3)
+#define MAX77686_RTCINT_RTC1S_MSK	BIT(4)
+#define MAX77686_RTCINT_WTSR_MSK	BIT(5)
+
 struct max77686_dev {
 	struct device *dev;
 	struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
@@ -224,11 +241,10 @@ struct max77686_dev {
 
 	struct regmap *regmap;		/* regmap for mfd */
 	struct regmap *rtc_regmap;	/* regmap for rtc */
-
-	struct irq_domain *irq_domain;
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *rtc_irq_data;
 
 	int irq;
-	int irq_gpio;
 	bool wakeup;
 	struct mutex irqlock;
 	int irq_masks_cur[MAX77686_IRQ_GROUP_NR];
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
index 46c0f32..4cbcc13 100644
--- a/include/linux/mfd/max77686.h
+++ b/include/linux/mfd/max77686.h
@@ -89,8 +89,6 @@ struct max77686_opmode_data {
 };
 
 struct max77686_platform_data {
-	/* IRQ */
-	int irq_gpio;
 	int ono;
 	int wakeup;
 
-- 
2.0.0.rc2


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

* [PATCH v4 01/14] mfd: max77686: Convert to use regmap_irq
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

By using the generic IRQ support in the Register map API, it
is possible to get rid max77686-irq.c and simplify the code.

Suggested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Acked-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
---

Changes since v3: None

Changes since v2:
 - Cleanup regmap irqchips on i2c_driver .remove function.
   Suggested by Doug Anderson.
 - Remove unused MAX77686_IRQ_NR enum. Suggested by Doug Anderson.

 drivers/mfd/Kconfig                  |   1 +
 drivers/mfd/Makefile                 |   2 +-
 drivers/mfd/max77686-irq.c           | 319 -----------------------------------
 drivers/mfd/max77686.c               |  97 ++++++++++-
 drivers/rtc/rtc-max77686.c           |  27 +--
 include/linux/mfd/max77686-private.h |  28 ++-
 include/linux/mfd/max77686.h         |   2 -
 7 files changed, 123 insertions(+), 353 deletions(-)
 delete mode 100644 drivers/mfd/max77686-irq.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index af0e83f..b53cc5e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -383,6 +383,7 @@ config MFD_MAX77686
 	depends on I2C=y
 	select MFD_CORE
 	select REGMAP_I2C
+	select REGMAP_IRQ
 	select IRQ_DOMAIN
 	help
 	  Say yes here to add support for Maxim Semiconductor MAX77686.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4e2bc25..f001487 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -115,7 +115,7 @@ da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
 obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
-obj-$(CONFIG_MFD_MAX77686)	+= max77686.o max77686-irq.o
+obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
diff --git a/drivers/mfd/max77686-irq.c b/drivers/mfd/max77686-irq.c
deleted file mode 100644
index cdc3280..0000000
--- a/drivers/mfd/max77686-irq.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * max77686-irq.c - Interrupt controller support for MAX77686
- *
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- * Chiwoong Byun <woong.byun@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This driver is based on max8997-irq.c
- */
-
-#include <linux/err.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mfd/max77686.h>
-#include <linux/mfd/max77686-private.h>
-#include <linux/irqdomain.h>
-#include <linux/regmap.h>
-
-enum {
-	MAX77686_DEBUG_IRQ_INFO = 1 << 0,
-	MAX77686_DEBUG_IRQ_MASK = 1 << 1,
-	MAX77686_DEBUG_IRQ_INT = 1 << 2,
-};
-
-static int debug_mask = 0;
-module_param(debug_mask, int, 0);
-MODULE_PARM_DESC(debug_mask, "Set debug_mask : 0x0=off 0x1=IRQ_INFO  0x2=IRQ_MASK 0x4=IRQ_INI)");
-
-static const u8 max77686_mask_reg[] = {
-	[PMIC_INT1] = MAX77686_REG_INT1MSK,
-	[PMIC_INT2] = MAX77686_REG_INT2MSK,
-	[RTC_INT] = MAX77686_RTC_INTM,
-};
-
-static struct regmap *max77686_get_regmap(struct max77686_dev *max77686,
-				enum max77686_irq_source src)
-{
-	switch (src) {
-	case PMIC_INT1 ... PMIC_INT2:
-		return max77686->regmap;
-	case RTC_INT:
-		return max77686->rtc_regmap;
-	default:
-		return ERR_PTR(-EINVAL);
-	}
-}
-
-struct max77686_irq_data {
-	int mask;
-	enum max77686_irq_source group;
-};
-
-#define DECLARE_IRQ(idx, _group, _mask)		\
-	[(idx)] = { .group = (_group), .mask = (_mask) }
-static const struct max77686_irq_data max77686_irqs[] = {
-	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONF,	PMIC_INT1, 1 << 0),
-	DECLARE_IRQ(MAX77686_PMICIRQ_PWRONR,	PMIC_INT1, 1 << 1),
-	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBF,	PMIC_INT1, 1 << 2),
-	DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBR,	PMIC_INT1, 1 << 3),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBF,	PMIC_INT1, 1 << 4),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBR,	PMIC_INT1, 1 << 5),
-	DECLARE_IRQ(MAX77686_PMICIRQ_ONKEY1S,	PMIC_INT1, 1 << 6),
-	DECLARE_IRQ(MAX77686_PMICIRQ_MRSTB,		PMIC_INT1, 1 << 7),
-	DECLARE_IRQ(MAX77686_PMICIRQ_140C,		PMIC_INT2, 1 << 0),
-	DECLARE_IRQ(MAX77686_PMICIRQ_120C,		PMIC_INT2, 1 << 1),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTC60S,		RTC_INT, 1 << 0),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA1,		RTC_INT, 1 << 1),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTCA2,		RTC_INT, 1 << 2),
-	DECLARE_IRQ(MAX77686_RTCIRQ_SMPL,		RTC_INT, 1 << 3),
-	DECLARE_IRQ(MAX77686_RTCIRQ_RTC1S,		RTC_INT, 1 << 4),
-	DECLARE_IRQ(MAX77686_RTCIRQ_WTSR,		RTC_INT, 1 << 5),
-};
-
-static void max77686_irq_lock(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s\n", __func__);
-
-	mutex_lock(&max77686->irqlock);
-}
-
-static void max77686_irq_sync_unlock(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	int i;
-
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
-		u8 mask_reg = max77686_mask_reg[i];
-		struct regmap *map = max77686_get_regmap(max77686, i);
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-			pr_debug("%s: mask_reg[%d]=0x%x, cur=0x%x\n",
-			__func__, i, mask_reg, max77686->irq_masks_cur[i]);
-
-		if (mask_reg == MAX77686_REG_INVALID ||
-				IS_ERR_OR_NULL(map))
-			continue;
-
-		max77686->irq_masks_cache[i] = max77686->irq_masks_cur[i];
-
-		regmap_write(map, max77686_mask_reg[i],
-				max77686->irq_masks_cur[i]);
-	}
-
-	mutex_unlock(&max77686->irqlock);
-}
-
-static const inline struct max77686_irq_data *to_max77686_irq(int irq)
-{
-	struct irq_data *data = irq_get_irq_data(irq);
-	return &max77686_irqs[data->hwirq];
-}
-
-static void max77686_irq_mask(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
-
-	max77686->irq_masks_cur[irq_data->group] |= irq_data->mask;
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s: group=%d, cur=0x%x\n",
-			__func__, irq_data->group,
-			max77686->irq_masks_cur[irq_data->group]);
-}
-
-static void max77686_irq_unmask(struct irq_data *data)
-{
-	struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
-	const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
-
-	max77686->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
-		pr_info("%s: group=%d, cur=0x%x\n",
-			__func__, irq_data->group,
-			max77686->irq_masks_cur[irq_data->group]);
-}
-
-static struct irq_chip max77686_irq_chip = {
-	.name			= "max77686",
-	.irq_bus_lock		= max77686_irq_lock,
-	.irq_bus_sync_unlock	= max77686_irq_sync_unlock,
-	.irq_mask		= max77686_irq_mask,
-	.irq_unmask		= max77686_irq_unmask,
-};
-
-static irqreturn_t max77686_irq_thread(int irq, void *data)
-{
-	struct max77686_dev *max77686 = data;
-	unsigned int irq_reg[MAX77686_IRQ_GROUP_NR] = {};
-	unsigned int irq_src;
-	int ret;
-	int i, cur_irq;
-
-	ret = regmap_read(max77686->regmap,  MAX77686_REG_INTSRC, &irq_src);
-	if (ret < 0) {
-		dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-				ret);
-		return IRQ_NONE;
-	}
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-		pr_info("%s: irq_src=0x%x\n", __func__, irq_src);
-
-	if (irq_src == MAX77686_IRQSRC_PMIC) {
-		ret = regmap_bulk_read(max77686->regmap,
-					 MAX77686_REG_INT1, irq_reg, 2);
-		if (ret < 0) {
-			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-					ret);
-			return IRQ_NONE;
-		}
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-			pr_info("%s: int1=0x%x, int2=0x%x\n", __func__,
-				 irq_reg[PMIC_INT1], irq_reg[PMIC_INT2]);
-	}
-
-	if (irq_src & MAX77686_IRQSRC_RTC) {
-		ret = regmap_read(max77686->rtc_regmap,
-					MAX77686_RTC_INT, &irq_reg[RTC_INT]);
-		if (ret < 0) {
-			dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
-					ret);
-			return IRQ_NONE;
-		}
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT)
-			pr_info("%s: rtc int=0x%x\n", __func__,
-							 irq_reg[RTC_INT]);
-
-	}
-
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++)
-		irq_reg[i] &= ~max77686->irq_masks_cur[i];
-
-	for (i = 0; i < MAX77686_IRQ_NR; i++) {
-		if (irq_reg[max77686_irqs[i].group] & max77686_irqs[i].mask) {
-			cur_irq = irq_find_mapping(max77686->irq_domain, i);
-			if (cur_irq)
-				handle_nested_irq(cur_irq);
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int max77686_irq_domain_map(struct irq_domain *d, unsigned int irq,
-					irq_hw_number_t hw)
-{
-	struct max77686_dev *max77686 = d->host_data;
-
-	irq_set_chip_data(irq, max77686);
-	irq_set_chip_and_handler(irq, &max77686_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 max77686_irq_domain_ops = {
-	.map = max77686_irq_domain_map,
-};
-
-int max77686_irq_init(struct max77686_dev *max77686)
-{
-	struct irq_domain *domain;
-	int i;
-	int ret;
-	int val;
-	struct regmap *map;
-
-	mutex_init(&max77686->irqlock);
-
-	if (max77686->irq_gpio && !max77686->irq) {
-		max77686->irq = gpio_to_irq(max77686->irq_gpio);
-
-		if (debug_mask & MAX77686_DEBUG_IRQ_INT) {
-			ret = gpio_request(max77686->irq_gpio, "pmic_irq");
-			if (ret < 0) {
-				dev_err(max77686->dev,
-					"Failed to request gpio %d with ret:"
-					"%d\n",	max77686->irq_gpio, ret);
-				return IRQ_NONE;
-			}
-
-			gpio_direction_input(max77686->irq_gpio);
-			val = gpio_get_value(max77686->irq_gpio);
-			gpio_free(max77686->irq_gpio);
-			pr_info("%s: gpio_irq=%x\n", __func__, val);
-		}
-	}
-
-	if (!max77686->irq) {
-		dev_err(max77686->dev, "irq is not specified\n");
-		return -ENODEV;
-	}
-
-	/* Mask individual interrupt sources */
-	for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
-		max77686->irq_masks_cur[i] = 0xff;
-		max77686->irq_masks_cache[i] = 0xff;
-		map = max77686_get_regmap(max77686, i);
-
-		if (IS_ERR_OR_NULL(map))
-			continue;
-		if (max77686_mask_reg[i] == MAX77686_REG_INVALID)
-			continue;
-
-		regmap_write(map, max77686_mask_reg[i], 0xff);
-	}
-	domain = irq_domain_add_linear(NULL, MAX77686_IRQ_NR,
-					&max77686_irq_domain_ops, max77686);
-	if (!domain) {
-		dev_err(max77686->dev, "could not create irq domain\n");
-		return -ENODEV;
-	}
-	max77686->irq_domain = domain;
-
-	ret = request_threaded_irq(max77686->irq, NULL, max77686_irq_thread,
-				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-				   "max77686-irq", max77686);
-
-	if (ret)
-		dev_err(max77686->dev, "Failed to request IRQ %d: %d\n",
-			max77686->irq, ret);
-
-
-	if (debug_mask & MAX77686_DEBUG_IRQ_INFO)
-		pr_info("%s-\n", __func__);
-
-	return 0;
-}
-
-void max77686_irq_exit(struct max77686_dev *max77686)
-{
-	if (max77686->irq)
-		free_irq(max77686->irq, max77686);
-}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index ce869ac..3cb41d0 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -25,6 +25,8 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/mfd/core.h>
@@ -46,6 +48,54 @@ static struct regmap_config max77686_regmap_config = {
 	.val_bits = 8,
 };
 
+static struct regmap_config max77686_rtc_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static const struct regmap_irq max77686_irqs[] = {
+	/* INT1 interrupts */
+	{ .reg_offset = 0, .mask = MAX77686_INT1_PWRONF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_PWRONR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_JIGONBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_JIGONBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ACOKBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ACOKBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_ONKEY1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_INT1_MRSTB_MSK, },
+	/* INT2 interrupts */
+	{ .reg_offset = 1, .mask = MAX77686_INT2_140C_MSK, },
+	{ .reg_offset = 1, .mask = MAX77686_INT2_120C_MSK, },
+};
+
+static const struct regmap_irq_chip max77686_irq_chip = {
+	.name			= "max77686-pmic",
+	.status_base		= MAX77686_REG_INT1,
+	.mask_base		= MAX77686_REG_INT1MSK,
+	.num_regs		= 2,
+	.irqs			= max77686_irqs,
+	.num_irqs		= ARRAY_SIZE(max77686_irqs),
+};
+
+static const struct regmap_irq max77686_rtc_irqs[] = {
+	/* RTC interrupts */
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, },
+};
+
+static const struct regmap_irq_chip max77686_rtc_irq_chip = {
+	.name			= "max77686-rtc",
+	.status_base		= MAX77686_RTC_INT,
+	.mask_base		= MAX77686_RTC_INTM,
+	.num_regs		= 1,
+	.irqs			= max77686_rtc_irqs,
+	.num_irqs		= ARRAY_SIZE(max77686_rtc_irqs),
+};
+
 #ifdef CONFIG_OF
 static const struct of_device_id max77686_pmic_dt_match[] = {
 	{.compatible = "maxim,max77686", .data = NULL},
@@ -101,7 +151,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 	max77686->type = id->driver_data;
 
 	max77686->wakeup = pdata->wakeup;
-	max77686->irq_gpio = pdata->irq_gpio;
 	max77686->irq = i2c->irq;
 
 	max77686->regmap = devm_regmap_init_i2c(i2c, &max77686_regmap_config);
@@ -117,8 +166,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 		dev_err(max77686->dev,
 			"device not found on this channel (this is not an error)\n");
 		return -ENODEV;
-	} else
-		dev_info(max77686->dev, "device found\n");
+	}
 
 	max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
 	if (!max77686->rtc) {
@@ -127,15 +175,48 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 	}
 	i2c_set_clientdata(max77686->rtc, max77686);
 
-	max77686_irq_init(max77686);
+	max77686->rtc_regmap = devm_regmap_init_i2c(max77686->rtc,
+						    &max77686_rtc_regmap_config);
+	if (IS_ERR(max77686->rtc_regmap)) {
+		ret = PTR_ERR(max77686->rtc_regmap);
+		dev_err(max77686->dev, "failed to allocate RTC regmap: %d\n",
+			ret);
+		goto err_unregister_i2c;
+	}
+
+	ret = regmap_add_irq_chip(max77686->regmap, max77686->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77686_irq_chip,
+				  &max77686->irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
+		goto err_unregister_i2c;
+	}
+	ret = regmap_add_irq_chip(max77686->rtc_regmap, max77686->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77686_rtc_irq_chip,
+				  &max77686->rtc_irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
+		goto err_del_irqc;
+	}
 
 	ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
 			      ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
 	if (ret < 0) {
-		mfd_remove_devices(max77686->dev);
-		i2c_unregister_device(max77686->rtc);
+		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+		goto err_del_rtc_irqc;
 	}
 
+	return 0;
+
+err_del_rtc_irqc:
+	regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
+err_del_irqc:
+	regmap_del_irq_chip(max77686->irq, max77686->irq_data);
+err_unregister_i2c:
+	i2c_unregister_device(max77686->rtc);
+
 	return ret;
 }
 
@@ -144,6 +225,10 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
 	struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
 
 	mfd_remove_devices(max77686->dev);
+
+	regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
+	regmap_del_irq_chip(max77686->irq, max77686->irq_data);
+
 	i2c_unregister_device(max77686->rtc);
 
 	return 0;
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 9efe118..d20a7f0 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -492,16 +492,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
 	return ret;
 }
 
-static struct regmap_config max77686_rtc_regmap_config = {
-	.reg_bits = 8,
-	.val_bits = 8,
-};
-
 static int max77686_rtc_probe(struct platform_device *pdev)
 {
 	struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
 	struct max77686_rtc_info *info;
-	int ret, virq;
+	int ret;
 
 	dev_info(&pdev->dev, "%s\n", __func__);
 
@@ -514,14 +509,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
 	info->dev = &pdev->dev;
 	info->max77686 = max77686;
 	info->rtc = max77686->rtc;
-	info->max77686->rtc_regmap = devm_regmap_init_i2c(info->max77686->rtc,
-					 &max77686_rtc_regmap_config);
-	if (IS_ERR(info->max77686->rtc_regmap)) {
-		ret = PTR_ERR(info->max77686->rtc_regmap);
-		dev_err(info->max77686->dev, "Failed to allocate register map: %d\n",
-				ret);
-		return ret;
-	}
+
 	platform_set_drvdata(pdev, info);
 
 	ret = max77686_rtc_init_reg(info);
@@ -550,15 +538,16 @@ static int max77686_rtc_probe(struct platform_device *pdev)
 			ret = -EINVAL;
 		goto err_rtc;
 	}
-	virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1);
-	if (!virq) {
+
+	info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
+					 MAX77686_RTCIRQ_RTCA1);
+	if (!info->virq) {
 		ret = -ENXIO;
 		goto err_rtc;
 	}
-	info->virq = virq;
 
-	ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
-				max77686_rtc_alarm_irq, 0, "rtc-alarm0", info);
+	ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
+				max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
 	if (ret < 0)
 		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
 			info->virq, ret);
diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h
index 8c75a9c..d86b547 100644
--- a/include/linux/mfd/max77686-private.h
+++ b/include/linux/mfd/max77686-private.h
@@ -205,16 +205,33 @@ enum max77686_irq {
 	MAX77686_PMICIRQ_140C,
 	MAX77686_PMICIRQ_120C,
 
-	MAX77686_RTCIRQ_RTC60S,
+	MAX77686_RTCIRQ_RTC60S = 0,
 	MAX77686_RTCIRQ_RTCA1,
 	MAX77686_RTCIRQ_RTCA2,
 	MAX77686_RTCIRQ_SMPL,
 	MAX77686_RTCIRQ_RTC1S,
 	MAX77686_RTCIRQ_WTSR,
-
-	MAX77686_IRQ_NR,
 };
 
+#define MAX77686_INT1_PWRONF_MSK	BIT(0)
+#define MAX77686_INT1_PWRONR_MSK	BIT(1)
+#define MAX77686_INT1_JIGONBF_MSK	BIT(2)
+#define MAX77686_INT1_JIGONBR_MSK	BIT(3)
+#define MAX77686_INT1_ACOKBF_MSK	BIT(4)
+#define MAX77686_INT1_ACOKBR_MSK	BIT(5)
+#define MAX77686_INT1_ONKEY1S_MSK	BIT(6)
+#define MAX77686_INT1_MRSTB_MSK		BIT(7)
+
+#define MAX77686_INT2_140C_MSK		BIT(0)
+#define MAX77686_INT2_120C_MSK		BIT(1)
+
+#define MAX77686_RTCINT_RTC60S_MSK	BIT(0)
+#define MAX77686_RTCINT_RTCA1_MSK	BIT(1)
+#define MAX77686_RTCINT_RTCA2_MSK	BIT(2)
+#define MAX77686_RTCINT_SMPL_MSK	BIT(3)
+#define MAX77686_RTCINT_RTC1S_MSK	BIT(4)
+#define MAX77686_RTCINT_WTSR_MSK	BIT(5)
+
 struct max77686_dev {
 	struct device *dev;
 	struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
@@ -224,11 +241,10 @@ struct max77686_dev {
 
 	struct regmap *regmap;		/* regmap for mfd */
 	struct regmap *rtc_regmap;	/* regmap for rtc */
-
-	struct irq_domain *irq_domain;
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *rtc_irq_data;
 
 	int irq;
-	int irq_gpio;
 	bool wakeup;
 	struct mutex irqlock;
 	int irq_masks_cur[MAX77686_IRQ_GROUP_NR];
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
index 46c0f32..4cbcc13 100644
--- a/include/linux/mfd/max77686.h
+++ b/include/linux/mfd/max77686.h
@@ -89,8 +89,6 @@ struct max77686_opmode_data {
 };
 
 struct max77686_platform_data {
-	/* IRQ */
-	int irq_gpio;
 	int ono;
 	int wakeup;
 
-- 
2.0.0.rc2

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

* [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system
  2014-06-25 19:03 ` Javier Martinez Canillas
  (?)
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

From: Doug Anderson <dianders@chromium.org>

The max77686 includes an RTC that keeps power during suspend.  It's
convenient to be able to use it as a wakeup source.

NOTE: due to wakeup ordering problems this patch alone doesn't work so
well on exynos5250-snow.  You also need something that brings the i2c
bus up before the max77686 wakeup runs.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Keep the note that this patch needs another change due wakeup
   ordering problems.

 drivers/rtc/rtc-max77686.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index d20a7f0..c1c6055 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -583,6 +583,33 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
 #endif /* MAX77686_RTC_WTSR_SMPL */
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max77686_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return enable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+
+static int max77686_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return disable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
+			 max77686_rtc_suspend, max77686_rtc_resume);
+
 static const struct platform_device_id rtc_id[] = {
 	{ "max77686-rtc", 0 },
 	{},
@@ -592,6 +619,7 @@ static struct platform_driver max77686_rtc_driver = {
 	.driver		= {
 		.name	= "max77686-rtc",
 		.owner	= THIS_MODULE,
+		.pm	= &max77686_rtc_pm_ops,
 	},
 	.probe		= max77686_rtc_probe,
 	.shutdown	= max77686_rtc_shutdown,
-- 
2.0.0.rc2


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

* [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Alessandro Zummo, Krzysztof Kozlowski, Kukjin Kim,
	Mike Turquette, Samuel Ortiz, Tomeu Vizoso, devicetree,
	linux-kernel, Liam Girdwood, Doug Anderson, linux-samsung-soc,
	Sjoerd Simons, Mark Brown, Olof Johansson, linux-arm-kernel,
	Daniel Stone

From: Doug Anderson <dianders@chromium.org>

The max77686 includes an RTC that keeps power during suspend.  It's
convenient to be able to use it as a wakeup source.

NOTE: due to wakeup ordering problems this patch alone doesn't work so
well on exynos5250-snow.  You also need something that brings the i2c
bus up before the max77686 wakeup runs.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Keep the note that this patch needs another change due wakeup
   ordering problems.

 drivers/rtc/rtc-max77686.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index d20a7f0..c1c6055 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -583,6 +583,33 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
 #endif /* MAX77686_RTC_WTSR_SMPL */
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max77686_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return enable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+
+static int max77686_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return disable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
+			 max77686_rtc_suspend, max77686_rtc_resume);
+
 static const struct platform_device_id rtc_id[] = {
 	{ "max77686-rtc", 0 },
 	{},
@@ -592,6 +619,7 @@ static struct platform_driver max77686_rtc_driver = {
 	.driver		= {
 		.name	= "max77686-rtc",
 		.owner	= THIS_MODULE,
+		.pm	= &max77686_rtc_pm_ops,
 	},
 	.probe		= max77686_rtc_probe,
 	.shutdown	= max77686_rtc_shutdown,
-- 
2.0.0.rc2

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

* [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

From: Doug Anderson <dianders@chromium.org>

The max77686 includes an RTC that keeps power during suspend.  It's
convenient to be able to use it as a wakeup source.

NOTE: due to wakeup ordering problems this patch alone doesn't work so
well on exynos5250-snow.  You also need something that brings the i2c
bus up before the max77686 wakeup runs.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Keep the note that this patch needs another change due wakeup
   ordering problems.

 drivers/rtc/rtc-max77686.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index d20a7f0..c1c6055 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -583,6 +583,33 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
 #endif /* MAX77686_RTC_WTSR_SMPL */
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max77686_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return enable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+
+static int max77686_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+		return disable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
+			 max77686_rtc_suspend, max77686_rtc_resume);
+
 static const struct platform_device_id rtc_id[] = {
 	{ "max77686-rtc", 0 },
 	{},
@@ -592,6 +619,7 @@ static struct platform_driver max77686_rtc_driver = {
 	.driver		= {
 		.name	= "max77686-rtc",
 		.owner	= THIS_MODULE,
+		.pm	= &max77686_rtc_pm_ops,
 	},
 	.probe		= max77686_rtc_probe,
 	.shutdown	= max77686_rtc_shutdown,
-- 
2.0.0.rc2

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

* [PATCH v4 03/14] clk: max77686: Add DT include for MAX77686 PMIC clock
  2014-06-25 19:03 ` Javier Martinez Canillas
  (?)
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

This patch adds a dt-binding include for Maxim 77686
PMIC clock IDs that can be to be shared between the
clk-max77686 clock driver and DeviceTree source files.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/clk-max77686.c                 |  7 +------
 include/dt-bindings/clock/maxim,max77686.h | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 6 deletions(-)
 create mode 100644 include/dt-bindings/clock/maxim,max77686.h

diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 3d7e8dd..185b611 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -30,12 +30,7 @@
 #include <linux/mutex.h>
 #include <linux/clkdev.h>
 
-enum {
-	MAX77686_CLK_AP = 0,
-	MAX77686_CLK_CP,
-	MAX77686_CLK_PMIC,
-	MAX77686_CLKS_NUM,
-};
+#include <dt-bindings/clock/maxim,max77686.h>
 
 struct max77686_clk {
 	struct max77686_dev *iodev;
diff --git a/include/dt-bindings/clock/maxim,max77686.h b/include/dt-bindings/clock/maxim,max77686.h
new file mode 100644
index 0000000..7b28b09
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77686.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77686 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77686_CLK_AP		0
+#define MAX77686_CLK_CP		1
+#define MAX77686_CLK_PMIC	2
+
+/* Total number of clocks. */
+#define MAX77686_CLKS_NUM		(MAX77686_CLK_PMIC + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H */
-- 
2.0.0.rc2


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

* [PATCH v4 03/14] clk: max77686: Add DT include for MAX77686 PMIC clock
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Alessandro Zummo, Krzysztof Kozlowski, Kukjin Kim,
	Mike Turquette, Samuel Ortiz, Tomeu Vizoso, devicetree,
	linux-kernel, Liam Girdwood, Doug Anderson, linux-samsung-soc,
	Sjoerd Simons, Mark Brown, Olof Johansson,
	Javier Martinez Canillas, linux-arm-kernel, Daniel Stone

This patch adds a dt-binding include for Maxim 77686
PMIC clock IDs that can be to be shared between the
clk-max77686 clock driver and DeviceTree source files.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/clk-max77686.c                 |  7 +------
 include/dt-bindings/clock/maxim,max77686.h | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 6 deletions(-)
 create mode 100644 include/dt-bindings/clock/maxim,max77686.h

diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 3d7e8dd..185b611 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -30,12 +30,7 @@
 #include <linux/mutex.h>
 #include <linux/clkdev.h>
 
-enum {
-	MAX77686_CLK_AP = 0,
-	MAX77686_CLK_CP,
-	MAX77686_CLK_PMIC,
-	MAX77686_CLKS_NUM,
-};
+#include <dt-bindings/clock/maxim,max77686.h>
 
 struct max77686_clk {
 	struct max77686_dev *iodev;
diff --git a/include/dt-bindings/clock/maxim,max77686.h b/include/dt-bindings/clock/maxim,max77686.h
new file mode 100644
index 0000000..7b28b09
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77686.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77686 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77686_CLK_AP		0
+#define MAX77686_CLK_CP		1
+#define MAX77686_CLK_PMIC	2
+
+/* Total number of clocks. */
+#define MAX77686_CLKS_NUM		(MAX77686_CLK_PMIC + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H */
-- 
2.0.0.rc2

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

* [PATCH v4 03/14] clk: max77686: Add DT include for MAX77686 PMIC clock
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a dt-binding include for Maxim 77686
PMIC clock IDs that can be to be shared between the
clk-max77686 clock driver and DeviceTree source files.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/clk-max77686.c                 |  7 +------
 include/dt-bindings/clock/maxim,max77686.h | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 6 deletions(-)
 create mode 100644 include/dt-bindings/clock/maxim,max77686.h

diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 3d7e8dd..185b611 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -30,12 +30,7 @@
 #include <linux/mutex.h>
 #include <linux/clkdev.h>
 
-enum {
-	MAX77686_CLK_AP = 0,
-	MAX77686_CLK_CP,
-	MAX77686_CLK_PMIC,
-	MAX77686_CLKS_NUM,
-};
+#include <dt-bindings/clock/maxim,max77686.h>
 
 struct max77686_clk {
 	struct max77686_dev *iodev;
diff --git a/include/dt-bindings/clock/maxim,max77686.h b/include/dt-bindings/clock/maxim,max77686.h
new file mode 100644
index 0000000..7b28b09
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77686.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77686 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77686_CLK_AP		0
+#define MAX77686_CLK_CP		1
+#define MAX77686_CLK_PMIC	2
+
+/* Total number of clocks. */
+#define MAX77686_CLKS_NUM		(MAX77686_CLK_PMIC + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H */
-- 
2.0.0.rc2

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

* [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Like most clock drivers, the Maxim 77686 PMIC clock binding
follows the convention that the "#clock-cells" property is
used to specify the number of cells in a clock provider.

But the binding document is not clear enough that it shall
be set to 1 since the PMIC support multiple clocks outputs.

Also, explain that the clocks identifiers are defined in a
header file that can be included by Device Tree source with
client nodes to avoid using magic numbers.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3:
 - Don't change clock-names property to make clear that it's
   the consumer clock name and should not match the producer clock.
   Suggested by Doug Anderson.

 Documentation/devicetree/bindings/clock/maxim,max77686.txt | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
index 96ce71b..48e00bb 100644
--- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt
+++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
@@ -9,13 +9,18 @@ The MAX77686 contains three 32.768khz clock outputs that can be controlled
 Following properties should be presend in main device node of the MFD chip.
 
 Required properties:
-- #clock-cells: simple one-cell clock specifier format is used, where the
-  only cell is used as an index of the clock inside the provider. Following
-  indices are allowed:
+
+- #clock-cells: from common clock binding; shall be set to 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
     - 0: 32khz_ap clock,
     - 1: 32khz_cp clock,
     - 2: 32khz_pmic clock.
 
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h
+header and can be used in device tree sources.
+
 Example: Node of the MFD chip
 
 	max77686: max77686@09 {
@@ -34,5 +39,5 @@ Example: Clock consumer node
 		compatible = "bar,foo";
 		/* ... */
 		clock-names = "my-clock";
-		clocks = <&max77686 2>;
+		clocks = <&max77686 MAX77686_CLK_PMIC>;
 	};
-- 
2.0.0.rc2


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

* [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Like most clock drivers, the Maxim 77686 PMIC clock binding
follows the convention that the "#clock-cells" property is
used to specify the number of cells in a clock provider.

But the binding document is not clear enough that it shall
be set to 1 since the PMIC support multiple clocks outputs.

Also, explain that the clocks identifiers are defined in a
header file that can be included by Device Tree source with
client nodes to avoid using magic numbers.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3:
 - Don't change clock-names property to make clear that it's
   the consumer clock name and should not match the producer clock.
   Suggested by Doug Anderson.

 Documentation/devicetree/bindings/clock/maxim,max77686.txt | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
index 96ce71b..48e00bb 100644
--- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt
+++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
@@ -9,13 +9,18 @@ The MAX77686 contains three 32.768khz clock outputs that can be controlled
 Following properties should be presend in main device node of the MFD chip.
 
 Required properties:
-- #clock-cells: simple one-cell clock specifier format is used, where the
-  only cell is used as an index of the clock inside the provider. Following
-  indices are allowed:
+
+- #clock-cells: from common clock binding; shall be set to 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
     - 0: 32khz_ap clock,
     - 1: 32khz_cp clock,
     - 2: 32khz_pmic clock.
 
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h
+header and can be used in device tree sources.
+
 Example: Node of the MFD chip
 
 	max77686: max77686 at 09 {
@@ -34,5 +39,5 @@ Example: Clock consumer node
 		compatible = "bar,foo";
 		/* ... */
 		clock-names = "my-clock";
-		clocks = <&max77686 2>;
+		clocks = <&max77686 MAX77686_CLK_PMIC>;
 	};
-- 
2.0.0.rc2

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

* [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Maxim Integrated Power Management ICs are very similar with
regard to their clock outputs. Most of the clock drivers for
these chips are duplicating code and are simpler enough that
can be converted to use a generic driver to consolidate code
and avoid duplication.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Add current copyright information. Suggested by Krzysztof Kozlowski
 - Do a single allocation for struct max_gen_clk. Suggested by Krzysztof Kozlowski 

 drivers/clk/Kconfig       |   3 +
 drivers/clk/Makefile      |   1 +
 drivers/clk/clk-max-gen.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/clk-max-gen.h |  32 ++++++++
 4 files changed, 231 insertions(+)
 create mode 100644 drivers/clk/clk-max-gen.c
 create mode 100644 drivers/clk/clk-max-gen.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9f9c5ae..73f78e8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -32,6 +32,9 @@ config COMMON_CLK_WM831X
 
 source "drivers/clk/versatile/Kconfig"
 
+config COMMON_CLK_MAX_GEN
+        bool
+
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
 	depends on MFD_MAX77686
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 567f102..6c1aff6 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_BCM2835)		+= clk-bcm2835.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
+obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
new file mode 100644
index 0000000..3e9fa7e
--- /dev/null
+++ b/drivers/clk/clk-max-gen.c
@@ -0,0 +1,195 @@
+/*
+ * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+struct max_gen_clk {
+	struct regmap *regmap;
+	u32 mask;
+	u32 reg;
+	struct clk_hw hw;
+	struct clk_lookup *lookup;
+};
+
+static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
+{
+	return container_of(hw, struct max_gen_clk, hw);
+}
+
+static int max_gen_clk_prepare(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+	return regmap_update_bits(max_gen->regmap, max_gen->reg,
+				  max_gen->mask, max_gen->mask);
+}
+
+static void max_gen_clk_unprepare(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+	regmap_update_bits(max_gen->regmap, max_gen->reg,
+			   max_gen->mask, ~max_gen->mask);
+}
+
+static int max_gen_clk_is_prepared(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+	int ret;
+	u32 val;
+
+	ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
+
+	if (ret < 0)
+		return -EINVAL;
+
+	return val & max_gen->mask;
+}
+
+static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	return 32768;
+}
+
+struct clk_ops max_gen_clk_ops = {
+	.prepare	= max_gen_clk_prepare,
+	.unprepare	= max_gen_clk_unprepare,
+	.is_prepared	= max_gen_clk_is_prepared,
+	.recalc_rate	= max_gen_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(max_gen_clk_ops);
+
+static struct clk *max_gen_clk_register(struct device *dev,
+					struct max_gen_clk *max_gen)
+{
+	struct clk *clk;
+	struct clk_hw *hw = &max_gen->hw;
+
+	clk = clk_register(dev, hw);
+	if (IS_ERR(clk))
+		return clk;
+
+	max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
+	if (!max_gen->lookup)
+		return ERR_PTR(-ENOMEM);
+
+	max_gen->lookup->con_id = hw->init->name;
+	max_gen->lookup->clk = clk;
+
+	clkdev_add(max_gen->lookup);
+
+	return clk;
+}
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+		      u32 reg, struct clk_init_data *clks_init, int num_init)
+{
+	int i, ret;
+	struct max_gen_clk *max_gen_clks;
+	struct clk **clocks;
+	struct device *dev = &pdev->dev;
+
+	clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
+	if (!clocks)
+		return -ENOMEM;
+
+	max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
+				    * num_init, GFP_KERNEL);
+	if (!max_gen_clks)
+		return -ENOMEM;
+
+	for (i = 0; i < num_init; i++) {
+		max_gen_clks[i].regmap = regmap;
+		max_gen_clks[i].mask = 1 << i;
+		max_gen_clks[i].reg = reg;
+		max_gen_clks[i].hw.init = &clks_init[i];
+
+		clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
+		if (IS_ERR(clocks[i])) {
+			ret = PTR_ERR(clocks[i]);
+			dev_err(dev, "failed to register %s\n",
+				max_gen_clks[i].hw.init->name);
+			goto err_clocks;
+		}
+	}
+
+	platform_set_drvdata(pdev, clocks);
+
+	if (dev->of_node) {
+		struct clk_onecell_data *of_data;
+
+		of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
+		if (!of_data) {
+			ret = -ENOMEM;
+			goto err_clocks;
+		}
+
+		of_data->clks = clocks;
+		of_data->clk_num = num_init;
+		ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+					  of_data);
+
+		if (ret) {
+			dev_err(dev, "failed to register OF clock provider\n");
+			goto err_clocks;
+		}
+	}
+
+	return 0;
+
+err_clocks:
+	for (--i; i >= 0; --i) {
+		clkdev_drop(max_gen_clks[i].lookup);
+		clk_unregister(max_gen_clks[i].hw.clk);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_probe);
+
+int max_gen_clk_remove(struct platform_device *pdev, int num_init)
+{
+	struct clk **clocks = platform_get_drvdata(pdev);
+	struct device *dev = pdev->dev.parent;
+	int i;
+
+	if (dev->of_node)
+		of_clk_del_provider(dev->of_node);
+
+	for (i = 0; i < num_init; i++) {
+		struct clk_hw *hw = __clk_get_hw(clocks[i]);
+		struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+		clkdev_drop(max_gen->lookup);
+		clk_unregister(clocks[i]);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_remove);
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
new file mode 100644
index 0000000..997e86f
--- /dev/null
+++ b/drivers/clk/clk-max-gen.h
@@ -0,0 +1,32 @@
+/*
+ * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CLK_MAX_GEN_H__
+#define __CLK_MAX_GEN_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+		      u32 reg, struct clk_init_data *clks_init, int num_init);
+int max_gen_clk_remove(struct platform_device *pdev, int num_init);
+extern struct clk_ops max_gen_clk_ops;
+
+#endif /* __CLK_MAX_GEN_H__ */
-- 
2.0.0.rc2


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

* [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Maxim Integrated Power Management ICs are very similar with
regard to their clock outputs. Most of the clock drivers for
these chips are duplicating code and are simpler enough that
can be converted to use a generic driver to consolidate code
and avoid duplication.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Add current copyright information. Suggested by Krzysztof Kozlowski
 - Do a single allocation for struct max_gen_clk. Suggested by Krzysztof Kozlowski 

 drivers/clk/Kconfig       |   3 +
 drivers/clk/Makefile      |   1 +
 drivers/clk/clk-max-gen.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/clk-max-gen.h |  32 ++++++++
 4 files changed, 231 insertions(+)
 create mode 100644 drivers/clk/clk-max-gen.c
 create mode 100644 drivers/clk/clk-max-gen.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9f9c5ae..73f78e8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -32,6 +32,9 @@ config COMMON_CLK_WM831X
 
 source "drivers/clk/versatile/Kconfig"
 
+config COMMON_CLK_MAX_GEN
+        bool
+
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
 	depends on MFD_MAX77686
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 567f102..6c1aff6 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_BCM2835)		+= clk-bcm2835.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
+obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
new file mode 100644
index 0000000..3e9fa7e
--- /dev/null
+++ b/drivers/clk/clk-max-gen.c
@@ -0,0 +1,195 @@
+/*
+ * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+struct max_gen_clk {
+	struct regmap *regmap;
+	u32 mask;
+	u32 reg;
+	struct clk_hw hw;
+	struct clk_lookup *lookup;
+};
+
+static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
+{
+	return container_of(hw, struct max_gen_clk, hw);
+}
+
+static int max_gen_clk_prepare(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+	return regmap_update_bits(max_gen->regmap, max_gen->reg,
+				  max_gen->mask, max_gen->mask);
+}
+
+static void max_gen_clk_unprepare(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+	regmap_update_bits(max_gen->regmap, max_gen->reg,
+			   max_gen->mask, ~max_gen->mask);
+}
+
+static int max_gen_clk_is_prepared(struct clk_hw *hw)
+{
+	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+	int ret;
+	u32 val;
+
+	ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
+
+	if (ret < 0)
+		return -EINVAL;
+
+	return val & max_gen->mask;
+}
+
+static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	return 32768;
+}
+
+struct clk_ops max_gen_clk_ops = {
+	.prepare	= max_gen_clk_prepare,
+	.unprepare	= max_gen_clk_unprepare,
+	.is_prepared	= max_gen_clk_is_prepared,
+	.recalc_rate	= max_gen_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(max_gen_clk_ops);
+
+static struct clk *max_gen_clk_register(struct device *dev,
+					struct max_gen_clk *max_gen)
+{
+	struct clk *clk;
+	struct clk_hw *hw = &max_gen->hw;
+
+	clk = clk_register(dev, hw);
+	if (IS_ERR(clk))
+		return clk;
+
+	max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
+	if (!max_gen->lookup)
+		return ERR_PTR(-ENOMEM);
+
+	max_gen->lookup->con_id = hw->init->name;
+	max_gen->lookup->clk = clk;
+
+	clkdev_add(max_gen->lookup);
+
+	return clk;
+}
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+		      u32 reg, struct clk_init_data *clks_init, int num_init)
+{
+	int i, ret;
+	struct max_gen_clk *max_gen_clks;
+	struct clk **clocks;
+	struct device *dev = &pdev->dev;
+
+	clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
+	if (!clocks)
+		return -ENOMEM;
+
+	max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
+				    * num_init, GFP_KERNEL);
+	if (!max_gen_clks)
+		return -ENOMEM;
+
+	for (i = 0; i < num_init; i++) {
+		max_gen_clks[i].regmap = regmap;
+		max_gen_clks[i].mask = 1 << i;
+		max_gen_clks[i].reg = reg;
+		max_gen_clks[i].hw.init = &clks_init[i];
+
+		clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
+		if (IS_ERR(clocks[i])) {
+			ret = PTR_ERR(clocks[i]);
+			dev_err(dev, "failed to register %s\n",
+				max_gen_clks[i].hw.init->name);
+			goto err_clocks;
+		}
+	}
+
+	platform_set_drvdata(pdev, clocks);
+
+	if (dev->of_node) {
+		struct clk_onecell_data *of_data;
+
+		of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
+		if (!of_data) {
+			ret = -ENOMEM;
+			goto err_clocks;
+		}
+
+		of_data->clks = clocks;
+		of_data->clk_num = num_init;
+		ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+					  of_data);
+
+		if (ret) {
+			dev_err(dev, "failed to register OF clock provider\n");
+			goto err_clocks;
+		}
+	}
+
+	return 0;
+
+err_clocks:
+	for (--i; i >= 0; --i) {
+		clkdev_drop(max_gen_clks[i].lookup);
+		clk_unregister(max_gen_clks[i].hw.clk);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_probe);
+
+int max_gen_clk_remove(struct platform_device *pdev, int num_init)
+{
+	struct clk **clocks = platform_get_drvdata(pdev);
+	struct device *dev = pdev->dev.parent;
+	int i;
+
+	if (dev->of_node)
+		of_clk_del_provider(dev->of_node);
+
+	for (i = 0; i < num_init; i++) {
+		struct clk_hw *hw = __clk_get_hw(clocks[i]);
+		struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+		clkdev_drop(max_gen->lookup);
+		clk_unregister(clocks[i]);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_remove);
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
new file mode 100644
index 0000000..997e86f
--- /dev/null
+++ b/drivers/clk/clk-max-gen.h
@@ -0,0 +1,32 @@
+/*
+ * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CLK_MAX_GEN_H__
+#define __CLK_MAX_GEN_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+		      u32 reg, struct clk_init_data *clks_init, int num_init);
+int max_gen_clk_remove(struct platform_device *pdev, int num_init);
+extern struct clk_ops max_gen_clk_ops;
+
+#endif /* __CLK_MAX_GEN_H__ */
-- 
2.0.0.rc2

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

* [PATCH v4 06/14] clk: max77686: Convert to the generic max clock driver
  2014-06-25 19:03 ` Javier Martinez Canillas
  (?)
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Clocks drivers for Maxim PMIC are very similar so they can
be converted to use the generic Maxim clock driver.

Also, while being there use module_platform_driver() helper
macro to eliminate more boilerplate code.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/Kconfig        |   1 +
 drivers/clk/clk-max77686.c | 176 +++------------------------------------------
 2 files changed, 9 insertions(+), 168 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 73f78e8..3fd4270 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -38,6 +38,7 @@ config COMMON_CLK_MAX_GEN
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
 	depends on MFD_MAX77686
+	select COMMON_CLK_MAX_GEN
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 185b611..ed0beb4 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -31,187 +31,37 @@
 #include <linux/clkdev.h>
 
 #include <dt-bindings/clock/maxim,max77686.h>
-
-struct max77686_clk {
-	struct max77686_dev *iodev;
-	u32 mask;
-	struct clk_hw hw;
-	struct clk_lookup *lookup;
-};
-
-static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
-{
-	return container_of(hw, struct max77686_clk, hw);
-}
-
-static int max77686_clk_prepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	return regmap_update_bits(max77686->iodev->regmap,
-				  MAX77686_REG_32KHZ, max77686->mask,
-				  max77686->mask);
-}
-
-static void max77686_clk_unprepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	regmap_update_bits(max77686->iodev->regmap,
-		MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
-}
-
-static int max77686_clk_is_prepared(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-	int ret;
-	u32 val;
-
-	ret = regmap_read(max77686->iodev->regmap,
-				MAX77686_REG_32KHZ, &val);
-
-	if (ret < 0)
-		return -EINVAL;
-
-	return val & max77686->mask;
-}
-
-static unsigned long max77686_recalc_rate(struct clk_hw *hw,
-					  unsigned long parent_rate)
-{
-	return 32768;
-}
-
-static struct clk_ops max77686_clk_ops = {
-	.prepare	= max77686_clk_prepare,
-	.unprepare	= max77686_clk_unprepare,
-	.is_prepared	= max77686_clk_is_prepared,
-	.recalc_rate	= max77686_recalc_rate,
-};
+#include "clk-max-gen.h"
 
 static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
 	[MAX77686_CLK_AP] = {
 		.name = "32khz_ap",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_CP] = {
 		.name = "32khz_cp",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_PMIC] = {
 		.name = "32khz_pmic",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 };
 
-static struct clk *max77686_clk_register(struct device *dev,
-				struct max77686_clk *max77686)
-{
-	struct clk *clk;
-	struct clk_hw *hw = &max77686->hw;
-
-	clk = clk_register(dev, hw);
-	if (IS_ERR(clk))
-		return clk;
-
-	max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
-	if (!max77686->lookup)
-		return ERR_PTR(-ENOMEM);
-
-	max77686->lookup->con_id = hw->init->name;
-	max77686->lookup->clk = clk;
-
-	clkdev_add(max77686->lookup);
-
-	return clk;
-}
-
 static int max77686_clk_probe(struct platform_device *pdev)
 {
 	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM];
-	struct clk **clocks;
-	int i, ret;
-
-	clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *)
-					* MAX77686_CLKS_NUM, GFP_KERNEL);
-	if (!clocks)
-		return -ENOMEM;
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i] = devm_kzalloc(&pdev->dev,
-					sizeof(struct max77686_clk), GFP_KERNEL);
-		if (!max77686_clks[i])
-			return -ENOMEM;
-	}
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i]->iodev = iodev;
-		max77686_clks[i]->mask = 1 << i;
-		max77686_clks[i]->hw.init = &max77686_clks_init[i];
-
-		clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]);
-		if (IS_ERR(clocks[i])) {
-			ret = PTR_ERR(clocks[i]);
-			dev_err(&pdev->dev, "failed to register %s\n",
-				max77686_clks[i]->hw.init->name);
-			goto err_clocks;
-		}
-	}
-
-	platform_set_drvdata(pdev, clocks);
-
-	if (iodev->dev->of_node) {
-		struct clk_onecell_data *of_data;
-
-		of_data = devm_kzalloc(&pdev->dev,
-					sizeof(*of_data), GFP_KERNEL);
-		if (!of_data) {
-			ret = -ENOMEM;
-			goto err_clocks;
-		}
 
-		of_data->clks = clocks;
-		of_data->clk_num = MAX77686_CLKS_NUM;
-		ret = of_clk_add_provider(iodev->dev->of_node,
-					of_clk_src_onecell_get, of_data);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to register OF clock provider\n");
-			goto err_clocks;
-		}
-	}
-
-	return 0;
-
-err_clocks:
-	for (--i; i >= 0; --i) {
-		clkdev_drop(max77686_clks[i]->lookup);
-		clk_unregister(max77686_clks[i]->hw.clk);
-	}
-
-	return ret;
+	return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
+				 max77686_clks_init, MAX77686_CLKS_NUM);
 }
 
 static int max77686_clk_remove(struct platform_device *pdev)
 {
-	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct clk **clocks = platform_get_drvdata(pdev);
-	int i;
-
-	if (iodev->dev->of_node)
-		of_clk_del_provider(iodev->dev->of_node);
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		struct clk_hw *hw = __clk_get_hw(clocks[i]);
-		struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-		clkdev_drop(max77686->lookup);
-		clk_unregister(clocks[i]);
-	}
-	return 0;
+	return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
 }
 
 static const struct platform_device_id max77686_clk_id[] = {
@@ -230,17 +80,7 @@ static struct platform_driver max77686_clk_driver = {
 	.id_table = max77686_clk_id,
 };
 
-static int __init max77686_clk_init(void)
-{
-	return platform_driver_register(&max77686_clk_driver);
-}
-subsys_initcall(max77686_clk_init);
-
-static void __init max77686_clk_cleanup(void)
-{
-	platform_driver_unregister(&max77686_clk_driver);
-}
-module_exit(max77686_clk_cleanup);
+module_platform_driver(max77686_clk_driver);
 
 MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
 MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
-- 
2.0.0.rc2


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

* [PATCH v4 06/14] clk: max77686: Convert to the generic max clock driver
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Alessandro Zummo, Krzysztof Kozlowski, Kukjin Kim,
	Mike Turquette, Samuel Ortiz, Tomeu Vizoso, devicetree,
	linux-kernel, Liam Girdwood, Doug Anderson, linux-samsung-soc,
	Sjoerd Simons, Mark Brown, Olof Johansson,
	Javier Martinez Canillas, linux-arm-kernel, Daniel Stone

Clocks drivers for Maxim PMIC are very similar so they can
be converted to use the generic Maxim clock driver.

Also, while being there use module_platform_driver() helper
macro to eliminate more boilerplate code.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/Kconfig        |   1 +
 drivers/clk/clk-max77686.c | 176 +++------------------------------------------
 2 files changed, 9 insertions(+), 168 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 73f78e8..3fd4270 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -38,6 +38,7 @@ config COMMON_CLK_MAX_GEN
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
 	depends on MFD_MAX77686
+	select COMMON_CLK_MAX_GEN
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 185b611..ed0beb4 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -31,187 +31,37 @@
 #include <linux/clkdev.h>
 
 #include <dt-bindings/clock/maxim,max77686.h>
-
-struct max77686_clk {
-	struct max77686_dev *iodev;
-	u32 mask;
-	struct clk_hw hw;
-	struct clk_lookup *lookup;
-};
-
-static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
-{
-	return container_of(hw, struct max77686_clk, hw);
-}
-
-static int max77686_clk_prepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	return regmap_update_bits(max77686->iodev->regmap,
-				  MAX77686_REG_32KHZ, max77686->mask,
-				  max77686->mask);
-}
-
-static void max77686_clk_unprepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	regmap_update_bits(max77686->iodev->regmap,
-		MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
-}
-
-static int max77686_clk_is_prepared(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-	int ret;
-	u32 val;
-
-	ret = regmap_read(max77686->iodev->regmap,
-				MAX77686_REG_32KHZ, &val);
-
-	if (ret < 0)
-		return -EINVAL;
-
-	return val & max77686->mask;
-}
-
-static unsigned long max77686_recalc_rate(struct clk_hw *hw,
-					  unsigned long parent_rate)
-{
-	return 32768;
-}
-
-static struct clk_ops max77686_clk_ops = {
-	.prepare	= max77686_clk_prepare,
-	.unprepare	= max77686_clk_unprepare,
-	.is_prepared	= max77686_clk_is_prepared,
-	.recalc_rate	= max77686_recalc_rate,
-};
+#include "clk-max-gen.h"
 
 static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
 	[MAX77686_CLK_AP] = {
 		.name = "32khz_ap",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_CP] = {
 		.name = "32khz_cp",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_PMIC] = {
 		.name = "32khz_pmic",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 };
 
-static struct clk *max77686_clk_register(struct device *dev,
-				struct max77686_clk *max77686)
-{
-	struct clk *clk;
-	struct clk_hw *hw = &max77686->hw;
-
-	clk = clk_register(dev, hw);
-	if (IS_ERR(clk))
-		return clk;
-
-	max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
-	if (!max77686->lookup)
-		return ERR_PTR(-ENOMEM);
-
-	max77686->lookup->con_id = hw->init->name;
-	max77686->lookup->clk = clk;
-
-	clkdev_add(max77686->lookup);
-
-	return clk;
-}
-
 static int max77686_clk_probe(struct platform_device *pdev)
 {
 	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM];
-	struct clk **clocks;
-	int i, ret;
-
-	clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *)
-					* MAX77686_CLKS_NUM, GFP_KERNEL);
-	if (!clocks)
-		return -ENOMEM;
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i] = devm_kzalloc(&pdev->dev,
-					sizeof(struct max77686_clk), GFP_KERNEL);
-		if (!max77686_clks[i])
-			return -ENOMEM;
-	}
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i]->iodev = iodev;
-		max77686_clks[i]->mask = 1 << i;
-		max77686_clks[i]->hw.init = &max77686_clks_init[i];
-
-		clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]);
-		if (IS_ERR(clocks[i])) {
-			ret = PTR_ERR(clocks[i]);
-			dev_err(&pdev->dev, "failed to register %s\n",
-				max77686_clks[i]->hw.init->name);
-			goto err_clocks;
-		}
-	}
-
-	platform_set_drvdata(pdev, clocks);
-
-	if (iodev->dev->of_node) {
-		struct clk_onecell_data *of_data;
-
-		of_data = devm_kzalloc(&pdev->dev,
-					sizeof(*of_data), GFP_KERNEL);
-		if (!of_data) {
-			ret = -ENOMEM;
-			goto err_clocks;
-		}
 
-		of_data->clks = clocks;
-		of_data->clk_num = MAX77686_CLKS_NUM;
-		ret = of_clk_add_provider(iodev->dev->of_node,
-					of_clk_src_onecell_get, of_data);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to register OF clock provider\n");
-			goto err_clocks;
-		}
-	}
-
-	return 0;
-
-err_clocks:
-	for (--i; i >= 0; --i) {
-		clkdev_drop(max77686_clks[i]->lookup);
-		clk_unregister(max77686_clks[i]->hw.clk);
-	}
-
-	return ret;
+	return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
+				 max77686_clks_init, MAX77686_CLKS_NUM);
 }
 
 static int max77686_clk_remove(struct platform_device *pdev)
 {
-	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct clk **clocks = platform_get_drvdata(pdev);
-	int i;
-
-	if (iodev->dev->of_node)
-		of_clk_del_provider(iodev->dev->of_node);
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		struct clk_hw *hw = __clk_get_hw(clocks[i]);
-		struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-		clkdev_drop(max77686->lookup);
-		clk_unregister(clocks[i]);
-	}
-	return 0;
+	return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
 }
 
 static const struct platform_device_id max77686_clk_id[] = {
@@ -230,17 +80,7 @@ static struct platform_driver max77686_clk_driver = {
 	.id_table = max77686_clk_id,
 };
 
-static int __init max77686_clk_init(void)
-{
-	return platform_driver_register(&max77686_clk_driver);
-}
-subsys_initcall(max77686_clk_init);
-
-static void __init max77686_clk_cleanup(void)
-{
-	platform_driver_unregister(&max77686_clk_driver);
-}
-module_exit(max77686_clk_cleanup);
+module_platform_driver(max77686_clk_driver);
 
 MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
 MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
-- 
2.0.0.rc2

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

* [PATCH v4 06/14] clk: max77686: Convert to the generic max clock driver
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Clocks drivers for Maxim PMIC are very similar so they can
be converted to use the generic Maxim clock driver.

Also, while being there use module_platform_driver() helper
macro to eliminate more boilerplate code.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---

Changes since v3: None

 drivers/clk/Kconfig        |   1 +
 drivers/clk/clk-max77686.c | 176 +++------------------------------------------
 2 files changed, 9 insertions(+), 168 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 73f78e8..3fd4270 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -38,6 +38,7 @@ config COMMON_CLK_MAX_GEN
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
 	depends on MFD_MAX77686
+	select COMMON_CLK_MAX_GEN
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 185b611..ed0beb4 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -31,187 +31,37 @@
 #include <linux/clkdev.h>
 
 #include <dt-bindings/clock/maxim,max77686.h>
-
-struct max77686_clk {
-	struct max77686_dev *iodev;
-	u32 mask;
-	struct clk_hw hw;
-	struct clk_lookup *lookup;
-};
-
-static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
-{
-	return container_of(hw, struct max77686_clk, hw);
-}
-
-static int max77686_clk_prepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	return regmap_update_bits(max77686->iodev->regmap,
-				  MAX77686_REG_32KHZ, max77686->mask,
-				  max77686->mask);
-}
-
-static void max77686_clk_unprepare(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-	regmap_update_bits(max77686->iodev->regmap,
-		MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
-}
-
-static int max77686_clk_is_prepared(struct clk_hw *hw)
-{
-	struct max77686_clk *max77686 = to_max77686_clk(hw);
-	int ret;
-	u32 val;
-
-	ret = regmap_read(max77686->iodev->regmap,
-				MAX77686_REG_32KHZ, &val);
-
-	if (ret < 0)
-		return -EINVAL;
-
-	return val & max77686->mask;
-}
-
-static unsigned long max77686_recalc_rate(struct clk_hw *hw,
-					  unsigned long parent_rate)
-{
-	return 32768;
-}
-
-static struct clk_ops max77686_clk_ops = {
-	.prepare	= max77686_clk_prepare,
-	.unprepare	= max77686_clk_unprepare,
-	.is_prepared	= max77686_clk_is_prepared,
-	.recalc_rate	= max77686_recalc_rate,
-};
+#include "clk-max-gen.h"
 
 static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
 	[MAX77686_CLK_AP] = {
 		.name = "32khz_ap",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_CP] = {
 		.name = "32khz_cp",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 	[MAX77686_CLK_PMIC] = {
 		.name = "32khz_pmic",
-		.ops = &max77686_clk_ops,
+		.ops = &max_gen_clk_ops,
 		.flags = CLK_IS_ROOT,
 	},
 };
 
-static struct clk *max77686_clk_register(struct device *dev,
-				struct max77686_clk *max77686)
-{
-	struct clk *clk;
-	struct clk_hw *hw = &max77686->hw;
-
-	clk = clk_register(dev, hw);
-	if (IS_ERR(clk))
-		return clk;
-
-	max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
-	if (!max77686->lookup)
-		return ERR_PTR(-ENOMEM);
-
-	max77686->lookup->con_id = hw->init->name;
-	max77686->lookup->clk = clk;
-
-	clkdev_add(max77686->lookup);
-
-	return clk;
-}
-
 static int max77686_clk_probe(struct platform_device *pdev)
 {
 	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM];
-	struct clk **clocks;
-	int i, ret;
-
-	clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *)
-					* MAX77686_CLKS_NUM, GFP_KERNEL);
-	if (!clocks)
-		return -ENOMEM;
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i] = devm_kzalloc(&pdev->dev,
-					sizeof(struct max77686_clk), GFP_KERNEL);
-		if (!max77686_clks[i])
-			return -ENOMEM;
-	}
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		max77686_clks[i]->iodev = iodev;
-		max77686_clks[i]->mask = 1 << i;
-		max77686_clks[i]->hw.init = &max77686_clks_init[i];
-
-		clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]);
-		if (IS_ERR(clocks[i])) {
-			ret = PTR_ERR(clocks[i]);
-			dev_err(&pdev->dev, "failed to register %s\n",
-				max77686_clks[i]->hw.init->name);
-			goto err_clocks;
-		}
-	}
-
-	platform_set_drvdata(pdev, clocks);
-
-	if (iodev->dev->of_node) {
-		struct clk_onecell_data *of_data;
-
-		of_data = devm_kzalloc(&pdev->dev,
-					sizeof(*of_data), GFP_KERNEL);
-		if (!of_data) {
-			ret = -ENOMEM;
-			goto err_clocks;
-		}
 
-		of_data->clks = clocks;
-		of_data->clk_num = MAX77686_CLKS_NUM;
-		ret = of_clk_add_provider(iodev->dev->of_node,
-					of_clk_src_onecell_get, of_data);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to register OF clock provider\n");
-			goto err_clocks;
-		}
-	}
-
-	return 0;
-
-err_clocks:
-	for (--i; i >= 0; --i) {
-		clkdev_drop(max77686_clks[i]->lookup);
-		clk_unregister(max77686_clks[i]->hw.clk);
-	}
-
-	return ret;
+	return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
+				 max77686_clks_init, MAX77686_CLKS_NUM);
 }
 
 static int max77686_clk_remove(struct platform_device *pdev)
 {
-	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct clk **clocks = platform_get_drvdata(pdev);
-	int i;
-
-	if (iodev->dev->of_node)
-		of_clk_del_provider(iodev->dev->of_node);
-
-	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
-		struct clk_hw *hw = __clk_get_hw(clocks[i]);
-		struct max77686_clk *max77686 = to_max77686_clk(hw);
-
-		clkdev_drop(max77686->lookup);
-		clk_unregister(clocks[i]);
-	}
-	return 0;
+	return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
 }
 
 static const struct platform_device_id max77686_clk_id[] = {
@@ -230,17 +80,7 @@ static struct platform_driver max77686_clk_driver = {
 	.id_table = max77686_clk_id,
 };
 
-static int __init max77686_clk_init(void)
-{
-	return platform_driver_register(&max77686_clk_driver);
-}
-subsys_initcall(max77686_clk_init);
-
-static void __init max77686_clk_cleanup(void)
-{
-	platform_driver_unregister(&max77686_clk_driver);
-}
-module_exit(max77686_clk_cleanup);
+module_platform_driver(max77686_clk_driver);
 
 MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
 MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
-- 
2.0.0.rc2

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Maxim MAX77802 is a power management chip that contains 10 high
efficiency Buck regulators, 32 Low-dropout (LDO) regulators used
to power up application processors and peripherals, a 2-channel
32kHz clock outputs, a Real-Time-Clock (RTC) and a I2C interface
to program the individual regulators, clocks outputs and the RTC.

This patch adds the core support for MAX77802 PMIC and is based
on a driver added by Simon Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Remove unnecessary OOM error message since the mm subsystem already logs it. 

Changes since v2:
 - Split the DT binding docs in a separate patch and improve the documentation.
   Suggested by Mark Brown.
 - Add all the devices in the MFD driver instead of doing in separate patches.
   Suggested by Mark Brown.

Changes since v1:
 - Convert max77{686,802} to regmap irq API and get rid of max77{686,802}-irq.c
   suggested by Krzysztof Kozlowski.
 - Don't protect max77802 mfd_cells using Kconfig options since mfd core omits
   devices that don't match. Suggested by Lee Jones.
 - Change mfd driver to be tristate instead of boolean. Suggested by Mark Brown.
 - Change binding "voltage-regulators" property to "regulators" to be consistent
   with other PMIC drivers. Suggested by Mark Brown.
 - Use regulators node names instead of the deprecated "regulator-compatible"
   property. Suggested by Mark Brown.
 - Use the new descriptor-based GPIO interface instead of the deprecated
   integer based GPIO one. Suggested by Mark Brown.
 - Remove the type parameter from i2c_device_id table since was not used.
 - Fix device not found error message and remove unneeded device found message.

 drivers/mfd/Kconfig                  |  14 ++
 drivers/mfd/Makefile                 |   1 +
 drivers/mfd/max77802.c               | 366 +++++++++++++++++++++++++++++++++++
 include/linux/mfd/max77802-private.h | 307 +++++++++++++++++++++++++++++
 include/linux/mfd/max77802.h         | 121 ++++++++++++
 5 files changed, 809 insertions(+)
 create mode 100644 drivers/mfd/max77802.c
 create mode 100644 include/linux/mfd/max77802-private.h
 create mode 100644 include/linux/mfd/max77802.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b53cc5e..51c0716 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -406,6 +406,20 @@ config MFD_MAX77693
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MAX77802
+	tristate "Maxim Integrated MAX77802 PMIC Support"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	select IRQ_DOMAIN
+	help
+	  Say yes here to support for Maxim Integrated MAX77802.
+	  This is a Power Management IC with RTC on chip.
+	  This driver provides common support for accessing the device;
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
+
 config MFD_MAX8907
 	tristate "Maxim Semiconductor MAX8907 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f001487..e795bfe 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
+obj-$(CONFIG_MFD_MAX77802)      += max77802.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
diff --git a/drivers/mfd/max77802.c b/drivers/mfd/max77802.c
new file mode 100644
index 0000000..3d477fb
--- /dev/null
+++ b/drivers/mfd/max77802.c
@@ -0,0 +1,366 @@
+/*
+ * max77802.c - mfd core driver for the Maxim 77802
+ *
+ * Copyright (C) 2013-2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+
+static const struct mfd_cell max77802_devs[] = {
+	{ .name = "max77802-pmic", },
+	{ .name = "max77802-clk", },
+	{ .name = "max77802-rtc", },
+};
+
+static bool max77802_pmic_is_accessible_reg(struct device *dev,
+					    unsigned int reg)
+{
+	return (reg >= MAX77802_REG_DEVICE_ID && reg < MAX77802_REG_PMIC_END);
+}
+
+static bool max77802_rtc_is_accessible_reg(struct device *dev,
+					   unsigned int reg)
+{
+	return (reg >= MAX77802_RTC_INT && reg < MAX77802_RTC_END);
+}
+
+static bool max77802_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_accessible_reg(dev, reg) ||
+		max77802_rtc_is_accessible_reg(dev, reg));
+}
+
+static bool max77802_pmic_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (reg == MAX77802_REG_INTSRC || reg == MAX77802_REG_INT1 ||
+		reg == MAX77802_REG_INT2);
+}
+
+static bool max77802_rtc_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (reg == MAX77802_RTC_INT ||
+		reg == MAX77802_RTC_UPDATE0 ||
+		reg == MAX77802_RTC_UPDATE1);
+}
+
+static bool max77802_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_precious_reg(dev, reg) ||
+		max77802_rtc_is_precious_reg(dev, reg));
+}
+
+static bool max77802_pmic_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_is_precious_reg(dev, reg) ||
+		reg == MAX77802_REG_STATUS1 || reg == MAX77802_REG_STATUS2 ||
+		reg == MAX77802_REG_PWRON);
+}
+
+static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_rtc_is_precious_reg(dev, reg) ||
+		reg == MAX77802_RTC_SEC ||
+		reg == MAX77802_RTC_MIN ||
+		reg == MAX77802_RTC_HOUR ||
+		reg == MAX77802_RTC_WEEKDAY ||
+		reg == MAX77802_RTC_MONTH ||
+		reg == MAX77802_RTC_YEAR ||
+		reg == MAX77802_RTC_DATE);
+}
+
+static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_volatile_reg(dev, reg) ||
+		max77802_rtc_is_volatile_reg(dev, reg));
+}
+
+static struct regmap_config max77802_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = max77802_is_accessible_reg,
+	.readable_reg = max77802_is_accessible_reg,
+	.precious_reg = max77802_is_precious_reg,
+	.volatile_reg = max77802_is_volatile_reg,
+	.name = "max77802-pmic",
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct regmap_irq max77802_irqs[] = {
+	/* INT1 interrupts */
+	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ONKEY1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_MRSTB_MSK, },
+	/* INT2 interrupts */
+	{ .reg_offset = 1, .mask = MAX77802_INT2_140C_MSK, },
+	{ .reg_offset = 1, .mask = MAX77802_INT2_120C_MSK, },
+};
+
+static const struct regmap_irq_chip max77802_irq_chip = {
+	.name			= "max77802-pmic",
+	.status_base		= MAX77802_REG_INT1,
+	.mask_base		= MAX77802_REG_INT1MSK,
+	.num_regs		= 2,
+	.irqs			= max77802_irqs,
+	.num_irqs		= ARRAY_SIZE(max77802_irqs),
+};
+
+static const struct regmap_irq max77802_rtc_irqs[] = {
+	/* RTC interrupts */
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC60S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA1_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA2_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_SMPL_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_WTSR_MSK, },
+};
+
+static const struct regmap_irq_chip max77802_rtc_irq_chip = {
+	.name			= "max77802-rtc",
+	.status_base		= MAX77802_RTC_INT,
+	.mask_base		= MAX77802_RTC_INTM,
+	.num_regs		= 1,
+	.irqs			= max77802_rtc_irqs,
+	.num_irqs		= ARRAY_SIZE(max77802_rtc_irqs),
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id max77802_pmic_dt_match[] = {
+	{.compatible = "maxim,max77802", .data = NULL},
+	{},
+};
+
+static void max77802_dt_parse_dvs_gpio(struct device *dev,
+				       struct max77802_platform_data *pd,
+				       struct device_node *np)
+{
+	int i;
+
+	/*
+	 * NOTE: we don't consider GPIO errors fatal; board may have some lines
+	 * directly pulled high or low and thus doesn't specify them.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++)
+		pd->buck_gpio_dvs[i] =
+			devm_gpiod_get_index(dev, "max77802,pmic-buck-dvs", i);
+
+	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++)
+		pd->buck_gpio_selb[i] =
+			devm_gpiod_get_index(dev, "max77802,pmic-buck-selb", i);
+}
+
+static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
+								  *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct max77802_platform_data *pd;
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return NULL;
+
+	/* Read default index and ignore errors, since default is 0 */
+	of_property_read_u32(np, "max77802,pmic-buck-default-dvs-idx",
+			     &pd->buck_default_idx);
+
+	max77802_dt_parse_dvs_gpio(dev, pd, np);
+
+	dev->platform_data = pd;
+	return pd;
+}
+#else
+static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
+								  *dev)
+{
+	return 0;
+}
+#endif
+
+static int max77802_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct max77802_dev *max77802 = NULL;
+	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	unsigned int data;
+	int ret = 0;
+
+	if (i2c->dev.of_node)
+		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
+
+	if (!pdata) {
+		dev_err(&i2c->dev, "No platform data found.\n");
+		return -EIO;
+	}
+
+	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
+				GFP_KERNEL);
+	if (max77802 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max77802);
+
+	max77802->dev = &i2c->dev;
+	max77802->i2c = i2c;
+	max77802->type = id->driver_data;
+
+	max77802->wakeup = pdata->wakeup;
+	max77802->irq = i2c->irq;
+
+	max77802->regmap = devm_regmap_init_i2c(i2c, &max77802_regmap_config);
+	if (IS_ERR(max77802->regmap)) {
+		ret = PTR_ERR(max77802->regmap);
+		dev_err(max77802->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (regmap_read(max77802->regmap,
+			 MAX77802_REG_DEVICE_ID, &data) < 0) {
+		dev_err(max77802->dev,
+			"device not found on this channel\n");
+		return -ENODEV;
+	}
+
+	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77802_irq_chip,
+				  &max77802->irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77802_rtc_irq_chip,
+				  &max77802->rtc_irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
+		goto err_del_irqc;
+	}
+
+	ret = mfd_add_devices(max77802->dev, -1, max77802_devs,
+			      ARRAY_SIZE(max77802_devs), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+		goto err_del_rtc_irqc;
+	}
+
+	return 0;
+
+err_del_rtc_irqc:
+	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
+err_del_irqc:
+	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
+	return ret;
+}
+
+static int max77802_i2c_remove(struct i2c_client *i2c)
+{
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max77802->dev);
+
+	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
+	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
+
+	return 0;
+}
+
+static const struct i2c_device_id max77802_i2c_id[] = {
+	{ "max77802", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max77802_i2c_id);
+
+#ifdef CONFIG_PM_SLEEP
+static int max77802_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(max77802->irq);
+
+	disable_irq(max77802->irq);
+
+	return 0;
+}
+
+static int max77802_resume(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(max77802->irq);
+
+	enable_irq(max77802->irq);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(max77802_pm, max77802_suspend, max77802_resume);
+
+static struct i2c_driver max77802_i2c_driver = {
+	.driver = {
+		   .name = "max77802",
+		   .owner = THIS_MODULE,
+		   .pm = &max77802_pm,
+		   .of_match_table = of_match_ptr(max77802_pmic_dt_match),
+	},
+	.probe = max77802_i2c_probe,
+	.remove = max77802_i2c_remove,
+	.id_table = max77802_i2c_id,
+};
+
+static int __init max77802_i2c_init(void)
+{
+	return i2c_add_driver(&max77802_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max77802_i2c_init);
+
+static void __exit max77802_i2c_exit(void)
+{
+	i2c_del_driver(&max77802_i2c_driver);
+}
+module_exit(max77802_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 77802 multi-function core driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77802-private.h b/include/linux/mfd/max77802-private.h
new file mode 100644
index 0000000..7539ab4
--- /dev/null
+++ b/include/linux/mfd/max77802-private.h
@@ -0,0 +1,307 @@
+/*
+ * max77802-private.h - Voltage regulator driver for the Maxim 77802
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_MFD_MAX77802_PRIV_H
+#define __LINUX_MFD_MAX77802_PRIV_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#define MAX77802_REG_INVALID		(0xff)
+
+enum max77802_pmic_reg {
+	MAX77802_REG_DEVICE_ID		= 0x00,
+	MAX77802_REG_INTSRC		= 0x01,
+	MAX77802_REG_INT1		= 0x02,
+	MAX77802_REG_INT2		= 0x03,
+
+	MAX77802_REG_INT1MSK		= 0x04,
+	MAX77802_REG_INT2MSK		= 0x05,
+
+	MAX77802_REG_STATUS1		= 0x06,
+	MAX77802_REG_STATUS2		= 0x07,
+
+	MAX77802_REG_PWRON		= 0x08,
+	/* Reserved: 0x09 */
+	MAX77802_REG_MRSTB		= 0x0A,
+	MAX77802_REG_EPWRHOLD		= 0x0B,
+	/* Reserved: 0x0C-0x0D */
+	MAX77802_REG_BOOSTCTRL		= 0x0E,
+	MAX77802_REG_BOOSTOUT		= 0x0F,
+
+	MAX77802_REG_BUCK1CTRL		= 0x10,
+	MAX77802_REG_BUCK1DVS1		= 0x11,
+	MAX77802_REG_BUCK1DVS2		= 0x12,
+	MAX77802_REG_BUCK1DVS3		= 0x13,
+	MAX77802_REG_BUCK1DVS4		= 0x14,
+	MAX77802_REG_BUCK1DVS5		= 0x15,
+	MAX77802_REG_BUCK1DVS6		= 0x16,
+	MAX77802_REG_BUCK1DVS7		= 0x17,
+	MAX77802_REG_BUCK1DVS8		= 0x18,
+	/* Reserved: 0x19 */
+	MAX77802_REG_BUCK2CTRL1		= 0x1A,
+	MAX77802_REG_BUCK2CTRL2		= 0x1B,
+	MAX77802_REG_BUCK2PHTRAN	= 0x1C,
+	MAX77802_REG_BUCK2DVS1		= 0x1D,
+	MAX77802_REG_BUCK2DVS2		= 0x1E,
+	MAX77802_REG_BUCK2DVS3		= 0x1F,
+	MAX77802_REG_BUCK2DVS4		= 0x20,
+	MAX77802_REG_BUCK2DVS5		= 0x21,
+	MAX77802_REG_BUCK2DVS6		= 0x22,
+	MAX77802_REG_BUCK2DVS7		= 0x23,
+	MAX77802_REG_BUCK2DVS8		= 0x24,
+	/* Reserved: 0x25-0x26 */
+	MAX77802_REG_BUCK3CTRL1		= 0x27,
+	MAX77802_REG_BUCK3DVS1		= 0x28,
+	MAX77802_REG_BUCK3DVS2		= 0x29,
+	MAX77802_REG_BUCK3DVS3		= 0x2A,
+	MAX77802_REG_BUCK3DVS4		= 0x2B,
+	MAX77802_REG_BUCK3DVS5		= 0x2C,
+	MAX77802_REG_BUCK3DVS6		= 0x2D,
+	MAX77802_REG_BUCK3DVS7		= 0x2E,
+	MAX77802_REG_BUCK3DVS8		= 0x2F,
+	/* Reserved: 0x30-0x36 */
+	MAX77802_REG_BUCK4CTRL1		= 0x37,
+	MAX77802_REG_BUCK4DVS1		= 0x38,
+	MAX77802_REG_BUCK4DVS2		= 0x39,
+	MAX77802_REG_BUCK4DVS3		= 0x3A,
+	MAX77802_REG_BUCK4DVS4		= 0x3B,
+	MAX77802_REG_BUCK4DVS5		= 0x3C,
+	MAX77802_REG_BUCK4DVS6		= 0x3D,
+	MAX77802_REG_BUCK4DVS7		= 0x3E,
+	MAX77802_REG_BUCK4DVS8		= 0x3F,
+	/* Reserved: 0x40 */
+	MAX77802_REG_BUCK5CTRL		= 0x41,
+	MAX77802_REG_BUCK5OUT		= 0x42,
+	/* Reserved: 0x43 */
+	MAX77802_REG_BUCK6CTRL		= 0x44,
+	MAX77802_REG_BUCK6DVS1		= 0x45,
+	MAX77802_REG_BUCK6DVS2		= 0x46,
+	MAX77802_REG_BUCK6DVS3		= 0x47,
+	MAX77802_REG_BUCK6DVS4		= 0x48,
+	MAX77802_REG_BUCK6DVS5		= 0x49,
+	MAX77802_REG_BUCK6DVS6		= 0x4A,
+	MAX77802_REG_BUCK6DVS7		= 0x4B,
+	MAX77802_REG_BUCK6DVS8		= 0x4C,
+	/* Reserved: 0x4D */
+	MAX77802_REG_BUCK7CTRL		= 0x4E,
+	MAX77802_REG_BUCK7OUT		= 0x4F,
+	/* Reserved: 0x50 */
+	MAX77802_REG_BUCK8CTRL		= 0x51,
+	MAX77802_REG_BUCK8OUT		= 0x52,
+	/* Reserved: 0x53 */
+	MAX77802_REG_BUCK9CTRL		= 0x54,
+	MAX77802_REG_BUCK9OUT		= 0x55,
+	/* Reserved: 0x56 */
+	MAX77802_REG_BUCK10CTRL		= 0x57,
+	MAX77802_REG_BUCK10OUT		= 0x58,
+
+	/* Reserved: 0x59-0x5F */
+
+	MAX77802_REG_LDO1CTRL1		= 0x60,
+	MAX77802_REG_LDO2CTRL1		= 0x61,
+	MAX77802_REG_LDO3CTRL1		= 0x62,
+	MAX77802_REG_LDO4CTRL1		= 0x63,
+	MAX77802_REG_LDO5CTRL1		= 0x64,
+	MAX77802_REG_LDO6CTRL1		= 0x65,
+	MAX77802_REG_LDO7CTRL1		= 0x66,
+	MAX77802_REG_LDO8CTRL1		= 0x67,
+	MAX77802_REG_LDO9CTRL1		= 0x68,
+	MAX77802_REG_LDO10CTRL1		= 0x69,
+	MAX77802_REG_LDO11CTRL1		= 0x6A,
+	MAX77802_REG_LDO12CTRL1		= 0x6B,
+	MAX77802_REG_LDO13CTRL1		= 0x6C,
+	MAX77802_REG_LDO14CTRL1		= 0x6D,
+	MAX77802_REG_LDO15CTRL1		= 0x6E,
+	/* Reserved: 0x6F */
+	MAX77802_REG_LDO17CTRL1		= 0x70,
+	MAX77802_REG_LDO18CTRL1		= 0x71,
+	MAX77802_REG_LDO19CTRL1		= 0x72,
+	MAX77802_REG_LDO20CTRL1		= 0x73,
+	MAX77802_REG_LDO21CTRL1		= 0x74,
+	MAX77802_REG_LDO22CTRL1		= 0x75,
+	MAX77802_REG_LDO23CTRL1		= 0x76,
+	MAX77802_REG_LDO24CTRL1		= 0x77,
+	MAX77802_REG_LDO25CTRL1		= 0x78,
+	MAX77802_REG_LDO26CTRL1		= 0x79,
+	MAX77802_REG_LDO27CTRL1		= 0x7A,
+	MAX77802_REG_LDO28CTRL1		= 0x7B,
+	MAX77802_REG_LDO29CTRL1		= 0x7C,
+	MAX77802_REG_LDO30CTRL1		= 0x7D,
+	/* Reserved: 0x7E */
+	MAX77802_REG_LDO32CTRL1		= 0x7F,
+	MAX77802_REG_LDO33CTRL1		= 0x80,
+	MAX77802_REG_LDO34CTRL1		= 0x81,
+	MAX77802_REG_LDO35CTRL1		= 0x82,
+	/* Reserved: 0x83-0x8F */
+	MAX77802_REG_LDO1CTRL2		= 0x90,
+	MAX77802_REG_LDO2CTRL2		= 0x91,
+	MAX77802_REG_LDO3CTRL2		= 0x92,
+	MAX77802_REG_LDO4CTRL2		= 0x93,
+	MAX77802_REG_LDO5CTRL2		= 0x94,
+	MAX77802_REG_LDO6CTRL2		= 0x95,
+	MAX77802_REG_LDO7CTRL2		= 0x96,
+	MAX77802_REG_LDO8CTRL2		= 0x97,
+	MAX77802_REG_LDO9CTRL2		= 0x98,
+	MAX77802_REG_LDO10CTRL2		= 0x99,
+	MAX77802_REG_LDO11CTRL2		= 0x9A,
+	MAX77802_REG_LDO12CTRL2		= 0x9B,
+	MAX77802_REG_LDO13CTRL2		= 0x9C,
+	MAX77802_REG_LDO14CTRL2		= 0x9D,
+	MAX77802_REG_LDO15CTRL2		= 0x9E,
+	/* Reserved: 0x9F */
+	MAX77802_REG_LDO17CTRL2		= 0xA0,
+	MAX77802_REG_LDO18CTRL2		= 0xA1,
+	MAX77802_REG_LDO19CTRL2		= 0xA2,
+	MAX77802_REG_LDO20CTRL2		= 0xA3,
+	MAX77802_REG_LDO21CTRL2		= 0xA4,
+	MAX77802_REG_LDO22CTRL2		= 0xA5,
+	MAX77802_REG_LDO23CTRL2		= 0xA6,
+	MAX77802_REG_LDO24CTRL2		= 0xA7,
+	MAX77802_REG_LDO25CTRL2		= 0xA8,
+	MAX77802_REG_LDO26CTRL2		= 0xA9,
+	MAX77802_REG_LDO27CTRL2		= 0xAA,
+	MAX77802_REG_LDO28CTRL2		= 0xAB,
+	MAX77802_REG_LDO29CTRL2		= 0xAC,
+	MAX77802_REG_LDO30CTRL2		= 0xAD,
+	/* Reserved: 0xAE */
+	MAX77802_REG_LDO32CTRL2		= 0xAF,
+	MAX77802_REG_LDO33CTRL2		= 0xB0,
+	MAX77802_REG_LDO34CTRL2		= 0xB1,
+	MAX77802_REG_LDO35CTRL2		= 0xB2,
+	/* Reserved: 0xB3 */
+
+	MAX77802_REG_BBAT_CHG		= 0xB4,
+	MAX77802_REG_32KHZ		= 0xB5,
+
+	MAX77802_REG_PMIC_END		= 0xB6,
+};
+
+enum max77802_rtc_reg {
+	MAX77802_RTC_INT		= 0xC0,
+	MAX77802_RTC_INTM		= 0xC1,
+	MAX77802_RTC_CONTROLM		= 0xC2,
+	MAX77802_RTC_CONTROL		= 0xC3,
+	MAX77802_RTC_UPDATE0		= 0xC4,
+	MAX77802_RTC_UPDATE1		= 0xC5,
+	MAX77802_WTSR_SMPL_CNTL		= 0xC6,
+	MAX77802_RTC_SEC		= 0xC7,
+	MAX77802_RTC_MIN		= 0xC8,
+	MAX77802_RTC_HOUR		= 0xC9,
+	MAX77802_RTC_WEEKDAY		= 0xCA,
+	MAX77802_RTC_MONTH		= 0xCB,
+	MAX77802_RTC_YEAR		= 0xCC,
+	MAX77802_RTC_DATE		= 0xCD,
+	MAX77802_RTC_AE1		= 0xCE,
+	MAX77802_ALARM1_SEC		= 0xCF,
+	MAX77802_ALARM1_MIN		= 0xD0,
+	MAX77802_ALARM1_HOUR		= 0xD1,
+	MAX77802_ALARM1_WEEKDAY		= 0xD2,
+	MAX77802_ALARM1_MONTH		= 0xD3,
+	MAX77802_ALARM1_YEAR		= 0xD4,
+	MAX77802_ALARM1_DATE		= 0xD5,
+	MAX77802_RTC_AE2		= 0xD6,
+	MAX77802_ALARM2_SEC		= 0xD7,
+	MAX77802_ALARM2_MIN		= 0xD8,
+	MAX77802_ALARM2_HOUR		= 0xD9,
+	MAX77802_ALARM2_WEEKDAY		= 0xDA,
+	MAX77802_ALARM2_MONTH		= 0xDB,
+	MAX77802_ALARM2_YEAR		= 0xDC,
+	MAX77802_ALARM2_DATE		= 0xDD,
+
+	MAX77802_RTC_END		= 0xDF,
+};
+
+#define MAX77802_IRQSRC_PMIC            (0)
+#define MAX77802_IRQSRC_RTC	        BIT(0)
+
+enum max77802_irq_source {
+	PMIC_INT1 = 0,
+	PMIC_INT2,
+	RTC_INT,
+
+	MAX77802_IRQ_GROUP_NR,
+};
+
+enum max77802_irq {
+	MAX77802_PMICIRQ_PWRONF,
+	MAX77802_PMICIRQ_PWRONR,
+	MAX77802_PMICIRQ_JIGONBF,
+	MAX77802_PMICIRQ_JIGONBR,
+	MAX77802_PMICIRQ_ACOKBF,
+	MAX77802_PMICIRQ_ACOKBR,
+	MAX77802_PMICIRQ_ONKEY1S,
+	MAX77802_PMICIRQ_MRSTB,
+
+	MAX77802_PMICIRQ_140C,
+	MAX77802_PMICIRQ_120C,
+
+	MAX77802_RTCIRQ_RTC60S = 0,
+	MAX77802_RTCIRQ_RTCA1,
+	MAX77802_RTCIRQ_RTCA2,
+	MAX77802_RTCIRQ_SMPL,
+	MAX77802_RTCIRQ_RTC1S,
+	MAX77802_RTCIRQ_WTSR,
+};
+
+#define MAX77802_INT1_PWRONF_MSK	BIT(0)
+#define MAX77802_INT1_PWRONR_MSK	BIT(1)
+#define MAX77802_INT1_JIGONBF_MSK	BIT(2)
+#define MAX77802_INT1_JIGONBR_MSK	BIT(3)
+#define MAX77802_INT1_ACOKBF_MSK	BIT(4)
+#define MAX77802_INT1_ACOKBR_MSK	BIT(5)
+#define MAX77802_INT1_ONKEY1S_MSK	BIT(6)
+#define MAX77802_INT1_MRSTB_MSK		BIT(7)
+
+#define MAX77802_INT2_140C_MSK		BIT(0)
+#define MAX77802_INT2_120C_MSK		BIT(1)
+
+#define MAX77802_RTCINT_RTC60S_MSK	BIT(0)
+#define MAX77802_RTCINT_RTCA1_MSK	BIT(1)
+#define MAX77802_RTCINT_RTCA2_MSK	BIT(2)
+#define MAX77802_RTCINT_SMPL_MSK	BIT(3)
+#define MAX77802_RTCINT_RTC1S_MSK	BIT(4)
+#define MAX77802_RTCINT_WTSR_MSK	BIT(5)
+
+struct max77802_dev {
+	struct device *dev;
+	struct i2c_client *i2c; /* 0x09 / PMIC, Battery Control and RTC */
+
+	int type;
+
+	struct regmap *regmap;		/* regmap for mfd and rtc devices */
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *rtc_irq_data;
+
+	int irq;
+	bool wakeup;
+	struct mutex irqlock;
+	int irq_masks_cur[MAX77802_IRQ_GROUP_NR];
+	int irq_masks_cache[MAX77802_IRQ_GROUP_NR];
+};
+
+enum max77802_types {
+	TYPE_MAX77802,
+};
+
+extern int max77802_irq_init(struct max77802_dev *max77802);
+extern void max77802_irq_exit(struct max77802_dev *max77802);
+extern int max77802_irq_resume(struct max77802_dev *max77802);
+
+#endif /*  __LINUX_MFD_MAX77802_PRIV_H */
diff --git a/include/linux/mfd/max77802.h b/include/linux/mfd/max77802.h
new file mode 100644
index 0000000..45e5943
--- /dev/null
+++ b/include/linux/mfd/max77802.h
@@ -0,0 +1,121 @@
+/*
+ * max77802.h - Driver for the Maxim 77802
+ *
+ * Copyright (c) 2013-2014 Google, Inc
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.h
+ *
+ * MAX77802 has PMIC, RTC devices.
+ * The devices share the same I2C bus and included in
+ * this mfd driver.
+ */
+
+#ifndef __LINUX_MFD_MAX77802_H
+#define __LINUX_MFD_MAX77802_H
+
+#include <linux/regulator/consumer.h>
+
+/* MAX77802 regulator IDs - LDOS must come before BUCKs */
+enum max77802_regulators {
+	MAX77802_BUCK1 = 0,
+	MAX77802_BUCK2,
+	MAX77802_BUCK3,
+	MAX77802_BUCK4,
+	MAX77802_BUCK5,
+	MAX77802_BUCK6,
+	MAX77802_BUCK7,
+	MAX77802_BUCK8,
+	MAX77802_BUCK9,
+	MAX77802_BUCK10,
+	MAX77802_LDO1,
+	MAX77802_LDO2,
+	MAX77802_LDO3,
+	MAX77802_LDO4,
+	MAX77802_LDO5,
+	MAX77802_LDO6,
+	MAX77802_LDO7,
+	MAX77802_LDO8,
+	MAX77802_LDO9,
+	MAX77802_LDO10,
+	MAX77802_LDO11,
+	MAX77802_LDO12,
+	MAX77802_LDO13,
+	MAX77802_LDO14,
+	MAX77802_LDO15,
+	MAX77802_LDO17,
+	MAX77802_LDO18,
+	MAX77802_LDO19,
+	MAX77802_LDO20,
+	MAX77802_LDO21,
+	MAX77802_LDO23,
+	MAX77802_LDO24,
+	MAX77802_LDO25,
+	MAX77802_LDO26,
+	MAX77802_LDO27,
+	MAX77802_LDO28,
+	MAX77802_LDO29,
+	MAX77802_LDO30,
+	MAX77802_LDO32,
+	MAX77802_LDO33,
+	MAX77802_LDO34,
+	MAX77802_LDO35,
+
+	MAX77802_REG_MAX,
+};
+
+struct max77802_regulator_data {
+	int id;
+	int opmode;
+	struct regulator_init_data *initdata;
+	struct device_node *of_node;
+};
+
+enum max77802_opmode {
+	MAX77802_OPMODE_OFF,
+	MAX77802_OPMODE_STANDBY,
+	MAX77802_OPMODE_LP,
+	MAX77802_OPMODE_NORMAL,
+};
+
+struct max77802_opmode_data {
+	int id;
+	int mode;
+};
+
+struct max77802_platform_data {
+	/* IRQ */
+	int irq_gpio;
+	int ono;
+	int wakeup;
+
+	/* ---- PMIC ---- */
+	struct max77802_regulator_data *regulators;
+	int num_regulators;
+
+	struct max77802_opmode_data *opmode_data;
+
+	/*
+	 * GPIO-DVS feature is not fully enabled with the current version of
+	 * MAX77802 driver, but the driver does support using a DVS index other
+	 * than the default of 0.
+	 */
+	struct gpio_desc *buck_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */
+	int buck_default_idx; /* Default value of DVS1, 2, 3 */
+
+	struct gpio_desc *buck_gpio_selb[5]; /* 77802: 1, 2, 3, 4, 6 */
+};
+
+#endif /* __LINUX_MFD_MAX77802_H */
-- 
2.0.0.rc2


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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Maxim MAX77802 is a power management chip that contains 10 high
efficiency Buck regulators, 32 Low-dropout (LDO) regulators used
to power up application processors and peripherals, a 2-channel
32kHz clock outputs, a Real-Time-Clock (RTC) and a I2C interface
to program the individual regulators, clocks outputs and the RTC.

This patch adds the core support for MAX77802 PMIC and is based
on a driver added by Simon Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Remove unnecessary OOM error message since the mm subsystem already logs it. 

Changes since v2:
 - Split the DT binding docs in a separate patch and improve the documentation.
   Suggested by Mark Brown.
 - Add all the devices in the MFD driver instead of doing in separate patches.
   Suggested by Mark Brown.

Changes since v1:
 - Convert max77{686,802} to regmap irq API and get rid of max77{686,802}-irq.c
   suggested by Krzysztof Kozlowski.
 - Don't protect max77802 mfd_cells using Kconfig options since mfd core omits
   devices that don't match. Suggested by Lee Jones.
 - Change mfd driver to be tristate instead of boolean. Suggested by Mark Brown.
 - Change binding "voltage-regulators" property to "regulators" to be consistent
   with other PMIC drivers. Suggested by Mark Brown.
 - Use regulators node names instead of the deprecated "regulator-compatible"
   property. Suggested by Mark Brown.
 - Use the new descriptor-based GPIO interface instead of the deprecated
   integer based GPIO one. Suggested by Mark Brown.
 - Remove the type parameter from i2c_device_id table since was not used.
 - Fix device not found error message and remove unneeded device found message.

 drivers/mfd/Kconfig                  |  14 ++
 drivers/mfd/Makefile                 |   1 +
 drivers/mfd/max77802.c               | 366 +++++++++++++++++++++++++++++++++++
 include/linux/mfd/max77802-private.h | 307 +++++++++++++++++++++++++++++
 include/linux/mfd/max77802.h         | 121 ++++++++++++
 5 files changed, 809 insertions(+)
 create mode 100644 drivers/mfd/max77802.c
 create mode 100644 include/linux/mfd/max77802-private.h
 create mode 100644 include/linux/mfd/max77802.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b53cc5e..51c0716 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -406,6 +406,20 @@ config MFD_MAX77693
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MAX77802
+	tristate "Maxim Integrated MAX77802 PMIC Support"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	select IRQ_DOMAIN
+	help
+	  Say yes here to support for Maxim Integrated MAX77802.
+	  This is a Power Management IC with RTC on chip.
+	  This driver provides common support for accessing the device;
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
+
 config MFD_MAX8907
 	tristate "Maxim Semiconductor MAX8907 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f001487..e795bfe 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
+obj-$(CONFIG_MFD_MAX77802)      += max77802.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
diff --git a/drivers/mfd/max77802.c b/drivers/mfd/max77802.c
new file mode 100644
index 0000000..3d477fb
--- /dev/null
+++ b/drivers/mfd/max77802.c
@@ -0,0 +1,366 @@
+/*
+ * max77802.c - mfd core driver for the Maxim 77802
+ *
+ * Copyright (C) 2013-2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+
+static const struct mfd_cell max77802_devs[] = {
+	{ .name = "max77802-pmic", },
+	{ .name = "max77802-clk", },
+	{ .name = "max77802-rtc", },
+};
+
+static bool max77802_pmic_is_accessible_reg(struct device *dev,
+					    unsigned int reg)
+{
+	return (reg >= MAX77802_REG_DEVICE_ID && reg < MAX77802_REG_PMIC_END);
+}
+
+static bool max77802_rtc_is_accessible_reg(struct device *dev,
+					   unsigned int reg)
+{
+	return (reg >= MAX77802_RTC_INT && reg < MAX77802_RTC_END);
+}
+
+static bool max77802_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_accessible_reg(dev, reg) ||
+		max77802_rtc_is_accessible_reg(dev, reg));
+}
+
+static bool max77802_pmic_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (reg == MAX77802_REG_INTSRC || reg == MAX77802_REG_INT1 ||
+		reg == MAX77802_REG_INT2);
+}
+
+static bool max77802_rtc_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (reg == MAX77802_RTC_INT ||
+		reg == MAX77802_RTC_UPDATE0 ||
+		reg == MAX77802_RTC_UPDATE1);
+}
+
+static bool max77802_is_precious_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_precious_reg(dev, reg) ||
+		max77802_rtc_is_precious_reg(dev, reg));
+}
+
+static bool max77802_pmic_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_is_precious_reg(dev, reg) ||
+		reg == MAX77802_REG_STATUS1 || reg == MAX77802_REG_STATUS2 ||
+		reg == MAX77802_REG_PWRON);
+}
+
+static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_rtc_is_precious_reg(dev, reg) ||
+		reg == MAX77802_RTC_SEC ||
+		reg == MAX77802_RTC_MIN ||
+		reg == MAX77802_RTC_HOUR ||
+		reg == MAX77802_RTC_WEEKDAY ||
+		reg == MAX77802_RTC_MONTH ||
+		reg == MAX77802_RTC_YEAR ||
+		reg == MAX77802_RTC_DATE);
+}
+
+static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return (max77802_pmic_is_volatile_reg(dev, reg) ||
+		max77802_rtc_is_volatile_reg(dev, reg));
+}
+
+static struct regmap_config max77802_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = max77802_is_accessible_reg,
+	.readable_reg = max77802_is_accessible_reg,
+	.precious_reg = max77802_is_precious_reg,
+	.volatile_reg = max77802_is_volatile_reg,
+	.name = "max77802-pmic",
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct regmap_irq max77802_irqs[] = {
+	/* INT1 interrupts */
+	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBF_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBR_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_ONKEY1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_INT1_MRSTB_MSK, },
+	/* INT2 interrupts */
+	{ .reg_offset = 1, .mask = MAX77802_INT2_140C_MSK, },
+	{ .reg_offset = 1, .mask = MAX77802_INT2_120C_MSK, },
+};
+
+static const struct regmap_irq_chip max77802_irq_chip = {
+	.name			= "max77802-pmic",
+	.status_base		= MAX77802_REG_INT1,
+	.mask_base		= MAX77802_REG_INT1MSK,
+	.num_regs		= 2,
+	.irqs			= max77802_irqs,
+	.num_irqs		= ARRAY_SIZE(max77802_irqs),
+};
+
+static const struct regmap_irq max77802_rtc_irqs[] = {
+	/* RTC interrupts */
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC60S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA1_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA2_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_SMPL_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC1S_MSK, },
+	{ .reg_offset = 0, .mask = MAX77802_RTCINT_WTSR_MSK, },
+};
+
+static const struct regmap_irq_chip max77802_rtc_irq_chip = {
+	.name			= "max77802-rtc",
+	.status_base		= MAX77802_RTC_INT,
+	.mask_base		= MAX77802_RTC_INTM,
+	.num_regs		= 1,
+	.irqs			= max77802_rtc_irqs,
+	.num_irqs		= ARRAY_SIZE(max77802_rtc_irqs),
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id max77802_pmic_dt_match[] = {
+	{.compatible = "maxim,max77802", .data = NULL},
+	{},
+};
+
+static void max77802_dt_parse_dvs_gpio(struct device *dev,
+				       struct max77802_platform_data *pd,
+				       struct device_node *np)
+{
+	int i;
+
+	/*
+	 * NOTE: we don't consider GPIO errors fatal; board may have some lines
+	 * directly pulled high or low and thus doesn't specify them.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++)
+		pd->buck_gpio_dvs[i] =
+			devm_gpiod_get_index(dev, "max77802,pmic-buck-dvs", i);
+
+	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++)
+		pd->buck_gpio_selb[i] =
+			devm_gpiod_get_index(dev, "max77802,pmic-buck-selb", i);
+}
+
+static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
+								  *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct max77802_platform_data *pd;
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return NULL;
+
+	/* Read default index and ignore errors, since default is 0 */
+	of_property_read_u32(np, "max77802,pmic-buck-default-dvs-idx",
+			     &pd->buck_default_idx);
+
+	max77802_dt_parse_dvs_gpio(dev, pd, np);
+
+	dev->platform_data = pd;
+	return pd;
+}
+#else
+static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
+								  *dev)
+{
+	return 0;
+}
+#endif
+
+static int max77802_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct max77802_dev *max77802 = NULL;
+	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	unsigned int data;
+	int ret = 0;
+
+	if (i2c->dev.of_node)
+		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
+
+	if (!pdata) {
+		dev_err(&i2c->dev, "No platform data found.\n");
+		return -EIO;
+	}
+
+	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
+				GFP_KERNEL);
+	if (max77802 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max77802);
+
+	max77802->dev = &i2c->dev;
+	max77802->i2c = i2c;
+	max77802->type = id->driver_data;
+
+	max77802->wakeup = pdata->wakeup;
+	max77802->irq = i2c->irq;
+
+	max77802->regmap = devm_regmap_init_i2c(i2c, &max77802_regmap_config);
+	if (IS_ERR(max77802->regmap)) {
+		ret = PTR_ERR(max77802->regmap);
+		dev_err(max77802->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (regmap_read(max77802->regmap,
+			 MAX77802_REG_DEVICE_ID, &data) < 0) {
+		dev_err(max77802->dev,
+			"device not found on this channel\n");
+		return -ENODEV;
+	}
+
+	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77802_irq_chip,
+				  &max77802->irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
+				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+				  IRQF_SHARED, 0, &max77802_rtc_irq_chip,
+				  &max77802->rtc_irq_data);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
+		goto err_del_irqc;
+	}
+
+	ret = mfd_add_devices(max77802->dev, -1, max77802_devs,
+			      ARRAY_SIZE(max77802_devs), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+		goto err_del_rtc_irqc;
+	}
+
+	return 0;
+
+err_del_rtc_irqc:
+	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
+err_del_irqc:
+	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
+	return ret;
+}
+
+static int max77802_i2c_remove(struct i2c_client *i2c)
+{
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max77802->dev);
+
+	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
+	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
+
+	return 0;
+}
+
+static const struct i2c_device_id max77802_i2c_id[] = {
+	{ "max77802", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max77802_i2c_id);
+
+#ifdef CONFIG_PM_SLEEP
+static int max77802_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(max77802->irq);
+
+	disable_irq(max77802->irq);
+
+	return 0;
+}
+
+static int max77802_resume(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(max77802->irq);
+
+	enable_irq(max77802->irq);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(max77802_pm, max77802_suspend, max77802_resume);
+
+static struct i2c_driver max77802_i2c_driver = {
+	.driver = {
+		   .name = "max77802",
+		   .owner = THIS_MODULE,
+		   .pm = &max77802_pm,
+		   .of_match_table = of_match_ptr(max77802_pmic_dt_match),
+	},
+	.probe = max77802_i2c_probe,
+	.remove = max77802_i2c_remove,
+	.id_table = max77802_i2c_id,
+};
+
+static int __init max77802_i2c_init(void)
+{
+	return i2c_add_driver(&max77802_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max77802_i2c_init);
+
+static void __exit max77802_i2c_exit(void)
+{
+	i2c_del_driver(&max77802_i2c_driver);
+}
+module_exit(max77802_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 77802 multi-function core driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77802-private.h b/include/linux/mfd/max77802-private.h
new file mode 100644
index 0000000..7539ab4
--- /dev/null
+++ b/include/linux/mfd/max77802-private.h
@@ -0,0 +1,307 @@
+/*
+ * max77802-private.h - Voltage regulator driver for the Maxim 77802
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_MFD_MAX77802_PRIV_H
+#define __LINUX_MFD_MAX77802_PRIV_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#define MAX77802_REG_INVALID		(0xff)
+
+enum max77802_pmic_reg {
+	MAX77802_REG_DEVICE_ID		= 0x00,
+	MAX77802_REG_INTSRC		= 0x01,
+	MAX77802_REG_INT1		= 0x02,
+	MAX77802_REG_INT2		= 0x03,
+
+	MAX77802_REG_INT1MSK		= 0x04,
+	MAX77802_REG_INT2MSK		= 0x05,
+
+	MAX77802_REG_STATUS1		= 0x06,
+	MAX77802_REG_STATUS2		= 0x07,
+
+	MAX77802_REG_PWRON		= 0x08,
+	/* Reserved: 0x09 */
+	MAX77802_REG_MRSTB		= 0x0A,
+	MAX77802_REG_EPWRHOLD		= 0x0B,
+	/* Reserved: 0x0C-0x0D */
+	MAX77802_REG_BOOSTCTRL		= 0x0E,
+	MAX77802_REG_BOOSTOUT		= 0x0F,
+
+	MAX77802_REG_BUCK1CTRL		= 0x10,
+	MAX77802_REG_BUCK1DVS1		= 0x11,
+	MAX77802_REG_BUCK1DVS2		= 0x12,
+	MAX77802_REG_BUCK1DVS3		= 0x13,
+	MAX77802_REG_BUCK1DVS4		= 0x14,
+	MAX77802_REG_BUCK1DVS5		= 0x15,
+	MAX77802_REG_BUCK1DVS6		= 0x16,
+	MAX77802_REG_BUCK1DVS7		= 0x17,
+	MAX77802_REG_BUCK1DVS8		= 0x18,
+	/* Reserved: 0x19 */
+	MAX77802_REG_BUCK2CTRL1		= 0x1A,
+	MAX77802_REG_BUCK2CTRL2		= 0x1B,
+	MAX77802_REG_BUCK2PHTRAN	= 0x1C,
+	MAX77802_REG_BUCK2DVS1		= 0x1D,
+	MAX77802_REG_BUCK2DVS2		= 0x1E,
+	MAX77802_REG_BUCK2DVS3		= 0x1F,
+	MAX77802_REG_BUCK2DVS4		= 0x20,
+	MAX77802_REG_BUCK2DVS5		= 0x21,
+	MAX77802_REG_BUCK2DVS6		= 0x22,
+	MAX77802_REG_BUCK2DVS7		= 0x23,
+	MAX77802_REG_BUCK2DVS8		= 0x24,
+	/* Reserved: 0x25-0x26 */
+	MAX77802_REG_BUCK3CTRL1		= 0x27,
+	MAX77802_REG_BUCK3DVS1		= 0x28,
+	MAX77802_REG_BUCK3DVS2		= 0x29,
+	MAX77802_REG_BUCK3DVS3		= 0x2A,
+	MAX77802_REG_BUCK3DVS4		= 0x2B,
+	MAX77802_REG_BUCK3DVS5		= 0x2C,
+	MAX77802_REG_BUCK3DVS6		= 0x2D,
+	MAX77802_REG_BUCK3DVS7		= 0x2E,
+	MAX77802_REG_BUCK3DVS8		= 0x2F,
+	/* Reserved: 0x30-0x36 */
+	MAX77802_REG_BUCK4CTRL1		= 0x37,
+	MAX77802_REG_BUCK4DVS1		= 0x38,
+	MAX77802_REG_BUCK4DVS2		= 0x39,
+	MAX77802_REG_BUCK4DVS3		= 0x3A,
+	MAX77802_REG_BUCK4DVS4		= 0x3B,
+	MAX77802_REG_BUCK4DVS5		= 0x3C,
+	MAX77802_REG_BUCK4DVS6		= 0x3D,
+	MAX77802_REG_BUCK4DVS7		= 0x3E,
+	MAX77802_REG_BUCK4DVS8		= 0x3F,
+	/* Reserved: 0x40 */
+	MAX77802_REG_BUCK5CTRL		= 0x41,
+	MAX77802_REG_BUCK5OUT		= 0x42,
+	/* Reserved: 0x43 */
+	MAX77802_REG_BUCK6CTRL		= 0x44,
+	MAX77802_REG_BUCK6DVS1		= 0x45,
+	MAX77802_REG_BUCK6DVS2		= 0x46,
+	MAX77802_REG_BUCK6DVS3		= 0x47,
+	MAX77802_REG_BUCK6DVS4		= 0x48,
+	MAX77802_REG_BUCK6DVS5		= 0x49,
+	MAX77802_REG_BUCK6DVS6		= 0x4A,
+	MAX77802_REG_BUCK6DVS7		= 0x4B,
+	MAX77802_REG_BUCK6DVS8		= 0x4C,
+	/* Reserved: 0x4D */
+	MAX77802_REG_BUCK7CTRL		= 0x4E,
+	MAX77802_REG_BUCK7OUT		= 0x4F,
+	/* Reserved: 0x50 */
+	MAX77802_REG_BUCK8CTRL		= 0x51,
+	MAX77802_REG_BUCK8OUT		= 0x52,
+	/* Reserved: 0x53 */
+	MAX77802_REG_BUCK9CTRL		= 0x54,
+	MAX77802_REG_BUCK9OUT		= 0x55,
+	/* Reserved: 0x56 */
+	MAX77802_REG_BUCK10CTRL		= 0x57,
+	MAX77802_REG_BUCK10OUT		= 0x58,
+
+	/* Reserved: 0x59-0x5F */
+
+	MAX77802_REG_LDO1CTRL1		= 0x60,
+	MAX77802_REG_LDO2CTRL1		= 0x61,
+	MAX77802_REG_LDO3CTRL1		= 0x62,
+	MAX77802_REG_LDO4CTRL1		= 0x63,
+	MAX77802_REG_LDO5CTRL1		= 0x64,
+	MAX77802_REG_LDO6CTRL1		= 0x65,
+	MAX77802_REG_LDO7CTRL1		= 0x66,
+	MAX77802_REG_LDO8CTRL1		= 0x67,
+	MAX77802_REG_LDO9CTRL1		= 0x68,
+	MAX77802_REG_LDO10CTRL1		= 0x69,
+	MAX77802_REG_LDO11CTRL1		= 0x6A,
+	MAX77802_REG_LDO12CTRL1		= 0x6B,
+	MAX77802_REG_LDO13CTRL1		= 0x6C,
+	MAX77802_REG_LDO14CTRL1		= 0x6D,
+	MAX77802_REG_LDO15CTRL1		= 0x6E,
+	/* Reserved: 0x6F */
+	MAX77802_REG_LDO17CTRL1		= 0x70,
+	MAX77802_REG_LDO18CTRL1		= 0x71,
+	MAX77802_REG_LDO19CTRL1		= 0x72,
+	MAX77802_REG_LDO20CTRL1		= 0x73,
+	MAX77802_REG_LDO21CTRL1		= 0x74,
+	MAX77802_REG_LDO22CTRL1		= 0x75,
+	MAX77802_REG_LDO23CTRL1		= 0x76,
+	MAX77802_REG_LDO24CTRL1		= 0x77,
+	MAX77802_REG_LDO25CTRL1		= 0x78,
+	MAX77802_REG_LDO26CTRL1		= 0x79,
+	MAX77802_REG_LDO27CTRL1		= 0x7A,
+	MAX77802_REG_LDO28CTRL1		= 0x7B,
+	MAX77802_REG_LDO29CTRL1		= 0x7C,
+	MAX77802_REG_LDO30CTRL1		= 0x7D,
+	/* Reserved: 0x7E */
+	MAX77802_REG_LDO32CTRL1		= 0x7F,
+	MAX77802_REG_LDO33CTRL1		= 0x80,
+	MAX77802_REG_LDO34CTRL1		= 0x81,
+	MAX77802_REG_LDO35CTRL1		= 0x82,
+	/* Reserved: 0x83-0x8F */
+	MAX77802_REG_LDO1CTRL2		= 0x90,
+	MAX77802_REG_LDO2CTRL2		= 0x91,
+	MAX77802_REG_LDO3CTRL2		= 0x92,
+	MAX77802_REG_LDO4CTRL2		= 0x93,
+	MAX77802_REG_LDO5CTRL2		= 0x94,
+	MAX77802_REG_LDO6CTRL2		= 0x95,
+	MAX77802_REG_LDO7CTRL2		= 0x96,
+	MAX77802_REG_LDO8CTRL2		= 0x97,
+	MAX77802_REG_LDO9CTRL2		= 0x98,
+	MAX77802_REG_LDO10CTRL2		= 0x99,
+	MAX77802_REG_LDO11CTRL2		= 0x9A,
+	MAX77802_REG_LDO12CTRL2		= 0x9B,
+	MAX77802_REG_LDO13CTRL2		= 0x9C,
+	MAX77802_REG_LDO14CTRL2		= 0x9D,
+	MAX77802_REG_LDO15CTRL2		= 0x9E,
+	/* Reserved: 0x9F */
+	MAX77802_REG_LDO17CTRL2		= 0xA0,
+	MAX77802_REG_LDO18CTRL2		= 0xA1,
+	MAX77802_REG_LDO19CTRL2		= 0xA2,
+	MAX77802_REG_LDO20CTRL2		= 0xA3,
+	MAX77802_REG_LDO21CTRL2		= 0xA4,
+	MAX77802_REG_LDO22CTRL2		= 0xA5,
+	MAX77802_REG_LDO23CTRL2		= 0xA6,
+	MAX77802_REG_LDO24CTRL2		= 0xA7,
+	MAX77802_REG_LDO25CTRL2		= 0xA8,
+	MAX77802_REG_LDO26CTRL2		= 0xA9,
+	MAX77802_REG_LDO27CTRL2		= 0xAA,
+	MAX77802_REG_LDO28CTRL2		= 0xAB,
+	MAX77802_REG_LDO29CTRL2		= 0xAC,
+	MAX77802_REG_LDO30CTRL2		= 0xAD,
+	/* Reserved: 0xAE */
+	MAX77802_REG_LDO32CTRL2		= 0xAF,
+	MAX77802_REG_LDO33CTRL2		= 0xB0,
+	MAX77802_REG_LDO34CTRL2		= 0xB1,
+	MAX77802_REG_LDO35CTRL2		= 0xB2,
+	/* Reserved: 0xB3 */
+
+	MAX77802_REG_BBAT_CHG		= 0xB4,
+	MAX77802_REG_32KHZ		= 0xB5,
+
+	MAX77802_REG_PMIC_END		= 0xB6,
+};
+
+enum max77802_rtc_reg {
+	MAX77802_RTC_INT		= 0xC0,
+	MAX77802_RTC_INTM		= 0xC1,
+	MAX77802_RTC_CONTROLM		= 0xC2,
+	MAX77802_RTC_CONTROL		= 0xC3,
+	MAX77802_RTC_UPDATE0		= 0xC4,
+	MAX77802_RTC_UPDATE1		= 0xC5,
+	MAX77802_WTSR_SMPL_CNTL		= 0xC6,
+	MAX77802_RTC_SEC		= 0xC7,
+	MAX77802_RTC_MIN		= 0xC8,
+	MAX77802_RTC_HOUR		= 0xC9,
+	MAX77802_RTC_WEEKDAY		= 0xCA,
+	MAX77802_RTC_MONTH		= 0xCB,
+	MAX77802_RTC_YEAR		= 0xCC,
+	MAX77802_RTC_DATE		= 0xCD,
+	MAX77802_RTC_AE1		= 0xCE,
+	MAX77802_ALARM1_SEC		= 0xCF,
+	MAX77802_ALARM1_MIN		= 0xD0,
+	MAX77802_ALARM1_HOUR		= 0xD1,
+	MAX77802_ALARM1_WEEKDAY		= 0xD2,
+	MAX77802_ALARM1_MONTH		= 0xD3,
+	MAX77802_ALARM1_YEAR		= 0xD4,
+	MAX77802_ALARM1_DATE		= 0xD5,
+	MAX77802_RTC_AE2		= 0xD6,
+	MAX77802_ALARM2_SEC		= 0xD7,
+	MAX77802_ALARM2_MIN		= 0xD8,
+	MAX77802_ALARM2_HOUR		= 0xD9,
+	MAX77802_ALARM2_WEEKDAY		= 0xDA,
+	MAX77802_ALARM2_MONTH		= 0xDB,
+	MAX77802_ALARM2_YEAR		= 0xDC,
+	MAX77802_ALARM2_DATE		= 0xDD,
+
+	MAX77802_RTC_END		= 0xDF,
+};
+
+#define MAX77802_IRQSRC_PMIC            (0)
+#define MAX77802_IRQSRC_RTC	        BIT(0)
+
+enum max77802_irq_source {
+	PMIC_INT1 = 0,
+	PMIC_INT2,
+	RTC_INT,
+
+	MAX77802_IRQ_GROUP_NR,
+};
+
+enum max77802_irq {
+	MAX77802_PMICIRQ_PWRONF,
+	MAX77802_PMICIRQ_PWRONR,
+	MAX77802_PMICIRQ_JIGONBF,
+	MAX77802_PMICIRQ_JIGONBR,
+	MAX77802_PMICIRQ_ACOKBF,
+	MAX77802_PMICIRQ_ACOKBR,
+	MAX77802_PMICIRQ_ONKEY1S,
+	MAX77802_PMICIRQ_MRSTB,
+
+	MAX77802_PMICIRQ_140C,
+	MAX77802_PMICIRQ_120C,
+
+	MAX77802_RTCIRQ_RTC60S = 0,
+	MAX77802_RTCIRQ_RTCA1,
+	MAX77802_RTCIRQ_RTCA2,
+	MAX77802_RTCIRQ_SMPL,
+	MAX77802_RTCIRQ_RTC1S,
+	MAX77802_RTCIRQ_WTSR,
+};
+
+#define MAX77802_INT1_PWRONF_MSK	BIT(0)
+#define MAX77802_INT1_PWRONR_MSK	BIT(1)
+#define MAX77802_INT1_JIGONBF_MSK	BIT(2)
+#define MAX77802_INT1_JIGONBR_MSK	BIT(3)
+#define MAX77802_INT1_ACOKBF_MSK	BIT(4)
+#define MAX77802_INT1_ACOKBR_MSK	BIT(5)
+#define MAX77802_INT1_ONKEY1S_MSK	BIT(6)
+#define MAX77802_INT1_MRSTB_MSK		BIT(7)
+
+#define MAX77802_INT2_140C_MSK		BIT(0)
+#define MAX77802_INT2_120C_MSK		BIT(1)
+
+#define MAX77802_RTCINT_RTC60S_MSK	BIT(0)
+#define MAX77802_RTCINT_RTCA1_MSK	BIT(1)
+#define MAX77802_RTCINT_RTCA2_MSK	BIT(2)
+#define MAX77802_RTCINT_SMPL_MSK	BIT(3)
+#define MAX77802_RTCINT_RTC1S_MSK	BIT(4)
+#define MAX77802_RTCINT_WTSR_MSK	BIT(5)
+
+struct max77802_dev {
+	struct device *dev;
+	struct i2c_client *i2c; /* 0x09 / PMIC, Battery Control and RTC */
+
+	int type;
+
+	struct regmap *regmap;		/* regmap for mfd and rtc devices */
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *rtc_irq_data;
+
+	int irq;
+	bool wakeup;
+	struct mutex irqlock;
+	int irq_masks_cur[MAX77802_IRQ_GROUP_NR];
+	int irq_masks_cache[MAX77802_IRQ_GROUP_NR];
+};
+
+enum max77802_types {
+	TYPE_MAX77802,
+};
+
+extern int max77802_irq_init(struct max77802_dev *max77802);
+extern void max77802_irq_exit(struct max77802_dev *max77802);
+extern int max77802_irq_resume(struct max77802_dev *max77802);
+
+#endif /*  __LINUX_MFD_MAX77802_PRIV_H */
diff --git a/include/linux/mfd/max77802.h b/include/linux/mfd/max77802.h
new file mode 100644
index 0000000..45e5943
--- /dev/null
+++ b/include/linux/mfd/max77802.h
@@ -0,0 +1,121 @@
+/*
+ * max77802.h - Driver for the Maxim 77802
+ *
+ * Copyright (c) 2013-2014 Google, Inc
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.h
+ *
+ * MAX77802 has PMIC, RTC devices.
+ * The devices share the same I2C bus and included in
+ * this mfd driver.
+ */
+
+#ifndef __LINUX_MFD_MAX77802_H
+#define __LINUX_MFD_MAX77802_H
+
+#include <linux/regulator/consumer.h>
+
+/* MAX77802 regulator IDs - LDOS must come before BUCKs */
+enum max77802_regulators {
+	MAX77802_BUCK1 = 0,
+	MAX77802_BUCK2,
+	MAX77802_BUCK3,
+	MAX77802_BUCK4,
+	MAX77802_BUCK5,
+	MAX77802_BUCK6,
+	MAX77802_BUCK7,
+	MAX77802_BUCK8,
+	MAX77802_BUCK9,
+	MAX77802_BUCK10,
+	MAX77802_LDO1,
+	MAX77802_LDO2,
+	MAX77802_LDO3,
+	MAX77802_LDO4,
+	MAX77802_LDO5,
+	MAX77802_LDO6,
+	MAX77802_LDO7,
+	MAX77802_LDO8,
+	MAX77802_LDO9,
+	MAX77802_LDO10,
+	MAX77802_LDO11,
+	MAX77802_LDO12,
+	MAX77802_LDO13,
+	MAX77802_LDO14,
+	MAX77802_LDO15,
+	MAX77802_LDO17,
+	MAX77802_LDO18,
+	MAX77802_LDO19,
+	MAX77802_LDO20,
+	MAX77802_LDO21,
+	MAX77802_LDO23,
+	MAX77802_LDO24,
+	MAX77802_LDO25,
+	MAX77802_LDO26,
+	MAX77802_LDO27,
+	MAX77802_LDO28,
+	MAX77802_LDO29,
+	MAX77802_LDO30,
+	MAX77802_LDO32,
+	MAX77802_LDO33,
+	MAX77802_LDO34,
+	MAX77802_LDO35,
+
+	MAX77802_REG_MAX,
+};
+
+struct max77802_regulator_data {
+	int id;
+	int opmode;
+	struct regulator_init_data *initdata;
+	struct device_node *of_node;
+};
+
+enum max77802_opmode {
+	MAX77802_OPMODE_OFF,
+	MAX77802_OPMODE_STANDBY,
+	MAX77802_OPMODE_LP,
+	MAX77802_OPMODE_NORMAL,
+};
+
+struct max77802_opmode_data {
+	int id;
+	int mode;
+};
+
+struct max77802_platform_data {
+	/* IRQ */
+	int irq_gpio;
+	int ono;
+	int wakeup;
+
+	/* ---- PMIC ---- */
+	struct max77802_regulator_data *regulators;
+	int num_regulators;
+
+	struct max77802_opmode_data *opmode_data;
+
+	/*
+	 * GPIO-DVS feature is not fully enabled with the current version of
+	 * MAX77802 driver, but the driver does support using a DVS index other
+	 * than the default of 0.
+	 */
+	struct gpio_desc *buck_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */
+	int buck_default_idx; /* Default value of DVS1, 2, 3 */
+
+	struct gpio_desc *buck_gpio_selb[5]; /* 77802: 1, 2, 3, 4, 6 */
+};
+
+#endif /* __LINUX_MFD_MAX77802_H */
-- 
2.0.0.rc2

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

* [PATCH v4 08/14] mfd: max77802: Add DT binding documentation
  2014-06-25 19:03 ` Javier Martinez Canillas
  (?)
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Add Device Tree binding documentation for Maxim 77802 PMIC.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

Changes since v2:
 - Explain better the Dynamic Voltage Scaling (DVS) support in some Buck
   regulators and the max77802,pmic-buck-{dvs,selb}-gpios properties.
   Suggested by Mark Brown.

 Documentation/devicetree/bindings/mfd/max77802.txt | 97 ++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt

diff --git a/Documentation/devicetree/bindings/mfd/max77802.txt b/Documentation/devicetree/bindings/mfd/max77802.txt
new file mode 100644
index 0000000..f3b67c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77802.txt
@@ -0,0 +1,97 @@
+Maxim MAX77802 multi-function device
+
+MAX77802 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is
+interfaced to host controller using i2c interface. PMIC, Charger and RTC
+submodules are addressed using same i2c slave address.
+
+Buck regulators 1, 2, 3, 4 and 6 include Dynamic Voltage Scaling (DVS) that
+allows each output voltage to change dynamically. Each Buck output voltage
+is selected using a set of external inputs: DVS1-3 and SELB1, 2, 3 and 6.
+
+There are 8 DVS registers that can be used to configure the output voltage
+for each Buck regulator and which one is active is controled by DVSx lines.
+
+SELBx lines are used to control if individual Buck lines are ON or OFF.
+
+This document describes the binding for mfd device and PMIC submodule.
+
+Binding for the built-in 32k clock generator block is defined separately
+in bindings/clk/maxim,max77802.txt file.
+
+Required properties:
+- compatible : Must be "maxim,max77802";
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent : The parent interrupt controller.
+
+Optional properties:
+- max77802,pmic-buck-default-dvs-idx: We'll always write this DVS index in the
+  PMIC for Bucks with DVS.
+  NOTE: at the moment these bindings don't include enough details for actual
+  GPIO-DVS--this just lets you choose which single slot to use.
+
+- max77802,pmic-buck-dvs-gpios: A GPIO array where each GPIO is connected to a
+  DVS line. We'll try to set these GPIOs to match pmic-buck-default-dvs-idx at
+  probe time if they are defined. If some or all of these GPIOs are not defined
+  it's assumed that the board has any missing GPIOs hardwired to match
+  pmic-buck-default-dvs-idx.
+
+- max77802,pmic-buck-selb-gpios: A GPIO array where each GPIO is connected to a
+  SELBx line. Should be five values: 1, 2, 3, 4, 6. It is strongly suggested to
+  include these GPIOs if there's any chance that changing DVS GPIOs one line at
+  a time might glitch your DVS values.
+
+Optional node:
+- regulators : The regulators of max77802 have to be instantiated
+  under subnode named "regulators" using the following format.
+
+	regulator_name {
+		standard regulator constraints....
+	};
+	refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+  The regulator node name should be initialized with a string
+to get matched with their hardware counterparts as follow:
+
+	-LDOn 	:	for LDOs, where n can lie in range 1 to 35.
+			example: LDO1, LDO2, LDO35.
+	-BUCKn 	:	for BUCKs, where n can lie in range 1 to 10.
+			example: BUCK1, BUCK5, BUCK10.
+Example:
+
+	max77802@09 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&wakeup_eint>;
+		interrupts = <26 0>;
+		reg = <0x09>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 0>,
+					       <&gpj4 2 0>,
+					       <&gpj4 3 0>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 0>,
+						<&gph0 3 0>,
+						<&gph0 4 0>,
+						<&gph0 5 0>,
+						<&gph0 6 0>;
+
+		regulators {
+			ldo11_reg: LDO11 {
+				regulator-compatible = "LDO11";
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1900000>;
+				regulator-max-microvolt = <1900000>;
+				regulator-always-on;
+			};
+
+			buck1_reg {
+				regulator-compatible = "BUCK1";
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+	};
-- 
2.0.0.rc2


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

* [PATCH v4 08/14] mfd: max77802: Add DT binding documentation
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Alessandro Zummo, Krzysztof Kozlowski, Kukjin Kim,
	Mike Turquette, Samuel Ortiz, Tomeu Vizoso, devicetree,
	linux-kernel, Liam Girdwood, Doug Anderson, linux-samsung-soc,
	Sjoerd Simons, Mark Brown, Olof Johansson,
	Javier Martinez Canillas, linux-arm-kernel, Daniel Stone

Add Device Tree binding documentation for Maxim 77802 PMIC.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

Changes since v2:
 - Explain better the Dynamic Voltage Scaling (DVS) support in some Buck
   regulators and the max77802,pmic-buck-{dvs,selb}-gpios properties.
   Suggested by Mark Brown.

 Documentation/devicetree/bindings/mfd/max77802.txt | 97 ++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt

diff --git a/Documentation/devicetree/bindings/mfd/max77802.txt b/Documentation/devicetree/bindings/mfd/max77802.txt
new file mode 100644
index 0000000..f3b67c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77802.txt
@@ -0,0 +1,97 @@
+Maxim MAX77802 multi-function device
+
+MAX77802 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is
+interfaced to host controller using i2c interface. PMIC, Charger and RTC
+submodules are addressed using same i2c slave address.
+
+Buck regulators 1, 2, 3, 4 and 6 include Dynamic Voltage Scaling (DVS) that
+allows each output voltage to change dynamically. Each Buck output voltage
+is selected using a set of external inputs: DVS1-3 and SELB1, 2, 3 and 6.
+
+There are 8 DVS registers that can be used to configure the output voltage
+for each Buck regulator and which one is active is controled by DVSx lines.
+
+SELBx lines are used to control if individual Buck lines are ON or OFF.
+
+This document describes the binding for mfd device and PMIC submodule.
+
+Binding for the built-in 32k clock generator block is defined separately
+in bindings/clk/maxim,max77802.txt file.
+
+Required properties:
+- compatible : Must be "maxim,max77802";
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent : The parent interrupt controller.
+
+Optional properties:
+- max77802,pmic-buck-default-dvs-idx: We'll always write this DVS index in the
+  PMIC for Bucks with DVS.
+  NOTE: at the moment these bindings don't include enough details for actual
+  GPIO-DVS--this just lets you choose which single slot to use.
+
+- max77802,pmic-buck-dvs-gpios: A GPIO array where each GPIO is connected to a
+  DVS line. We'll try to set these GPIOs to match pmic-buck-default-dvs-idx at
+  probe time if they are defined. If some or all of these GPIOs are not defined
+  it's assumed that the board has any missing GPIOs hardwired to match
+  pmic-buck-default-dvs-idx.
+
+- max77802,pmic-buck-selb-gpios: A GPIO array where each GPIO is connected to a
+  SELBx line. Should be five values: 1, 2, 3, 4, 6. It is strongly suggested to
+  include these GPIOs if there's any chance that changing DVS GPIOs one line at
+  a time might glitch your DVS values.
+
+Optional node:
+- regulators : The regulators of max77802 have to be instantiated
+  under subnode named "regulators" using the following format.
+
+	regulator_name {
+		standard regulator constraints....
+	};
+	refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+  The regulator node name should be initialized with a string
+to get matched with their hardware counterparts as follow:
+
+	-LDOn 	:	for LDOs, where n can lie in range 1 to 35.
+			example: LDO1, LDO2, LDO35.
+	-BUCKn 	:	for BUCKs, where n can lie in range 1 to 10.
+			example: BUCK1, BUCK5, BUCK10.
+Example:
+
+	max77802@09 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&wakeup_eint>;
+		interrupts = <26 0>;
+		reg = <0x09>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 0>,
+					       <&gpj4 2 0>,
+					       <&gpj4 3 0>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 0>,
+						<&gph0 3 0>,
+						<&gph0 4 0>,
+						<&gph0 5 0>,
+						<&gph0 6 0>;
+
+		regulators {
+			ldo11_reg: LDO11 {
+				regulator-compatible = "LDO11";
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1900000>;
+				regulator-max-microvolt = <1900000>;
+				regulator-always-on;
+			};
+
+			buck1_reg {
+				regulator-compatible = "BUCK1";
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+	};
-- 
2.0.0.rc2

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

* [PATCH v4 08/14] mfd: max77802: Add DT binding documentation
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Add Device Tree binding documentation for Maxim 77802 PMIC.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

Changes since v2:
 - Explain better the Dynamic Voltage Scaling (DVS) support in some Buck
   regulators and the max77802,pmic-buck-{dvs,selb}-gpios properties.
   Suggested by Mark Brown.

 Documentation/devicetree/bindings/mfd/max77802.txt | 97 ++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt

diff --git a/Documentation/devicetree/bindings/mfd/max77802.txt b/Documentation/devicetree/bindings/mfd/max77802.txt
new file mode 100644
index 0000000..f3b67c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77802.txt
@@ -0,0 +1,97 @@
+Maxim MAX77802 multi-function device
+
+MAX77802 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is
+interfaced to host controller using i2c interface. PMIC, Charger and RTC
+submodules are addressed using same i2c slave address.
+
+Buck regulators 1, 2, 3, 4 and 6 include Dynamic Voltage Scaling (DVS) that
+allows each output voltage to change dynamically. Each Buck output voltage
+is selected using a set of external inputs: DVS1-3 and SELB1, 2, 3 and 6.
+
+There are 8 DVS registers that can be used to configure the output voltage
+for each Buck regulator and which one is active is controled by DVSx lines.
+
+SELBx lines are used to control if individual Buck lines are ON or OFF.
+
+This document describes the binding for mfd device and PMIC submodule.
+
+Binding for the built-in 32k clock generator block is defined separately
+in bindings/clk/maxim,max77802.txt file.
+
+Required properties:
+- compatible : Must be "maxim,max77802";
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent : The parent interrupt controller.
+
+Optional properties:
+- max77802,pmic-buck-default-dvs-idx: We'll always write this DVS index in the
+  PMIC for Bucks with DVS.
+  NOTE: at the moment these bindings don't include enough details for actual
+  GPIO-DVS--this just lets you choose which single slot to use.
+
+- max77802,pmic-buck-dvs-gpios: A GPIO array where each GPIO is connected to a
+  DVS line. We'll try to set these GPIOs to match pmic-buck-default-dvs-idx at
+  probe time if they are defined. If some or all of these GPIOs are not defined
+  it's assumed that the board has any missing GPIOs hardwired to match
+  pmic-buck-default-dvs-idx.
+
+- max77802,pmic-buck-selb-gpios: A GPIO array where each GPIO is connected to a
+  SELBx line. Should be five values: 1, 2, 3, 4, 6. It is strongly suggested to
+  include these GPIOs if there's any chance that changing DVS GPIOs one line at
+  a time might glitch your DVS values.
+
+Optional node:
+- regulators : The regulators of max77802 have to be instantiated
+  under subnode named "regulators" using the following format.
+
+	regulator_name {
+		standard regulator constraints....
+	};
+	refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+  The regulator node name should be initialized with a string
+to get matched with their hardware counterparts as follow:
+
+	-LDOn 	:	for LDOs, where n can lie in range 1 to 35.
+			example: LDO1, LDO2, LDO35.
+	-BUCKn 	:	for BUCKs, where n can lie in range 1 to 10.
+			example: BUCK1, BUCK5, BUCK10.
+Example:
+
+	max77802 at 09 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&wakeup_eint>;
+		interrupts = <26 0>;
+		reg = <0x09>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 0>,
+					       <&gpj4 2 0>,
+					       <&gpj4 3 0>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 0>,
+						<&gph0 3 0>,
+						<&gph0 4 0>,
+						<&gph0 5 0>,
+						<&gph0 6 0>;
+
+		regulators {
+			ldo11_reg: LDO11 {
+				regulator-compatible = "LDO11";
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1900000>;
+				regulator-max-microvolt = <1900000>;
+				regulator-always-on;
+			};
+
+			buck1_reg {
+				regulator-compatible = "BUCK1";
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+	};
-- 
2.0.0.rc2

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

* [PATCH v4 09/14] regmap: Add regmap_reg_copy function
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Some device drivers using the register map API need to copy the
value from one register to another. Even though it can be done
with a combination of regmap_read() and regmap_write(), it is
better to have a function to avoid code duplication and also it
sanity check and do it atomically by holding the regmap lock.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

 drivers/base/regmap/regmap.c | 34 ++++++++++++++++++++++++++++++++++
 include/linux/regmap.h       |  9 +++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 74d8c06..a2e0b04 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2555,6 +2555,40 @@ int regmap_parse_val(struct regmap *map, const void *buf,
 }
 EXPORT_SYMBOL_GPL(regmap_parse_val);
 
+/**
+ * regmap_reg_copy(): Copy a value from a single register to another one
+ *
+ * @map: Register map to operate on
+ * @dest: Register to copy the value to
+ * @src: Register to copy the value from
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_reg_copy(struct regmap *map, unsigned int dest, unsigned int src)
+{
+	int val;
+	int ret = 0;
+
+	if (dest == src)
+		return ret;
+
+	if (dest % map->reg_stride ||
+	    src % map->reg_stride)
+		return -EINVAL;
+
+	map->lock(map->lock_arg);
+
+	ret = _regmap_read(map, src, &val);
+	if (!ret)
+		ret = _regmap_write(map, dest, val);
+
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_reg_copy);
+
 static int __init regmap_initcall(void)
 {
 	regmap_debugfs_initcall();
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 7b0e4b4..116c22b 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -445,6 +445,8 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 int regmap_parse_val(struct regmap *map, const void *buf,
 				unsigned int *val);
 
+int regmap_reg_copy(struct regmap *map, unsigned int dest, unsigned int src);
+
 static inline bool regmap_reg_in_range(unsigned int reg,
 				       const struct regmap_range *range)
 {
@@ -723,6 +725,13 @@ static inline int regmap_parse_val(struct regmap *map, const void *buf,
 	return -EINVAL;
 }
 
+static inline int regmap_reg_copy(struct regmap *map, unsigned int dest,
+				  unsigned int src)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline struct regmap *dev_get_regmap(struct device *dev,
 					    const char *name)
 {
-- 
2.0.0.rc2


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

* [PATCH v4 09/14] regmap: Add regmap_reg_copy function
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Some device drivers using the register map API need to copy the
value from one register to another. Even though it can be done
with a combination of regmap_read() and regmap_write(), it is
better to have a function to avoid code duplication and also it
sanity check and do it atomically by holding the regmap lock.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

 drivers/base/regmap/regmap.c | 34 ++++++++++++++++++++++++++++++++++
 include/linux/regmap.h       |  9 +++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 74d8c06..a2e0b04 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2555,6 +2555,40 @@ int regmap_parse_val(struct regmap *map, const void *buf,
 }
 EXPORT_SYMBOL_GPL(regmap_parse_val);
 
+/**
+ * regmap_reg_copy(): Copy a value from a single register to another one
+ *
+ * @map: Register map to operate on
+ * @dest: Register to copy the value to
+ * @src: Register to copy the value from
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_reg_copy(struct regmap *map, unsigned int dest, unsigned int src)
+{
+	int val;
+	int ret = 0;
+
+	if (dest == src)
+		return ret;
+
+	if (dest % map->reg_stride ||
+	    src % map->reg_stride)
+		return -EINVAL;
+
+	map->lock(map->lock_arg);
+
+	ret = _regmap_read(map, src, &val);
+	if (!ret)
+		ret = _regmap_write(map, dest, val);
+
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_reg_copy);
+
 static int __init regmap_initcall(void)
 {
 	regmap_debugfs_initcall();
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 7b0e4b4..116c22b 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -445,6 +445,8 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 int regmap_parse_val(struct regmap *map, const void *buf,
 				unsigned int *val);
 
+int regmap_reg_copy(struct regmap *map, unsigned int dest, unsigned int src);
+
 static inline bool regmap_reg_in_range(unsigned int reg,
 				       const struct regmap_range *range)
 {
@@ -723,6 +725,13 @@ static inline int regmap_parse_val(struct regmap *map, const void *buf,
 	return -EINVAL;
 }
 
+static inline int regmap_reg_copy(struct regmap *map, unsigned int dest,
+				  unsigned int src)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline struct regmap *dev_get_regmap(struct device *dev,
 					    const char *name)
 {
-- 
2.0.0.rc2

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

* [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
(LDO) regulators. This patch adds support for all these regulators
found on the MAX77802 PMIC and is based on a driver added by Simon
Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Set the supply_name for regulators to lookup their parent supply node.
   Suggested by Mark Brown.
 - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
   Suggested by Doug Anderson.

Changes since v2:
 - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
 - Add a generic function to regmap core to copy registers instead of
   having a driver-specific function. Suggested by Mark Brown.
 - Remove unnecessary probe debug log. Suggested by Mark Brown.
 - Set struct regulator_config dev field to MFD instead of the platform dev.
   Suggested by Mark Brown.
 - Read the regulators operational mode from the hardware registers instead
   of setting to normal as default on probe. Suggested by Mark Brown.
 - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.

Changes since v1:
 - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
 - Fix .set_suspend_mode handler comment and split regulators ops for
   regulators that behave differently. Suggested by Mark Brown.
 - Use module_platform_driver() instead of having init/exit functions.
   Suggested by Mark Brown.
 - Use the new descriptor-based GPIO interface instead of the deprecated
   integer based GPIO one. Suggested by Mark Brown.
 - Look for "regulators" child node instead of "voltage-regulators" to be
   consistent with other PMIC drivers. Suggested by Mark Brown.

 drivers/regulator/Kconfig    |   9 +
 drivers/regulator/Makefile   |   1 +
 drivers/regulator/max77802.c | 694 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 704 insertions(+)
 create mode 100644 drivers/regulator/max77802.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 789eb46..283f172 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -377,6 +377,15 @@ config REGULATOR_MAX77693
 	  and one current regulator 'CHARGER'. This is suitable for
 	  Exynos-4x12 chips.
 
+config REGULATOR_MAX77802
+	tristate "Maxim 77802 regulator"
+	depends on MFD_MAX77802
+	help
+	  This driver controls a Maxim 77802 regulator
+	  via I2C bus. The provided regulator is suitable for
+	  Exynos5420/Exynos5800 SoCs to control various voltages.
+	  It includes support for control of voltage and ramp speed.
+
 config REGULATOR_MC13XXX_CORE
 	tristate
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d461110..2aea4b6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
+obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c
new file mode 100644
index 0000000..8fd70b6
--- /dev/null
+++ b/drivers/regulator/max77802.c
@@ -0,0 +1,694 @@
+/*
+ * max77802.c - Regulator driver for the Maxim 77802
+ *
+ * Copyright (C) 2013-2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+
+/* Default ramp delay in case it is not manually set */
+#define MAX77802_RAMP_DELAY		100000		/* uV/us */
+
+#define MAX77802_OPMODE_SHIFT_LDO	6
+#define MAX77802_OPMODE_BUCK234_SHIFT	4
+#define MAX77802_OPMODE_MASK		0x3
+
+#define MAX77802_VSEL_MASK		0x3F
+#define MAX77802_DVS_VSEL_MASK		0xFF
+
+#define MAX77802_RAMP_RATE_MASK_2BIT	0xC0
+#define MAX77802_RAMP_RATE_SHIFT_2BIT	6
+#define MAX77802_RAMP_RATE_MASK_4BIT	0xF0
+#define MAX77802_RAMP_RATE_SHIFT_4BIT	4
+
+/* MAX77802 has two register formats: 2-bit and 4-bit */
+static const unsigned int ramp_table_77802_2bit[] = {
+	12500,
+	25000,
+	50000,
+	100000,
+};
+
+static unsigned int ramp_table_77802_4bit[] = {
+	1000,	2000,	3030,	4000,
+	5000,	5880,	7140,	8330,
+	9090,	10000,	11110,	12500,
+	16670,	25000,	50000,	100000,
+};
+
+struct max77802_regulator_prv {
+	int num_regulators;
+	struct regulator_dev *rdev[MAX77802_REG_MAX];
+	unsigned int opmode[MAX77802_REG_MAX];
+};
+
+static int max77802_get_opmode_shift(int id)
+{
+	if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35)
+		return MAX77802_OPMODE_SHIFT_LDO;
+	else if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 &&
+					  id <= MAX77802_BUCK10))
+		return 0;
+	else if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4)
+		return MAX77802_OPMODE_BUCK234_SHIFT;
+	else
+		return -EINVAL;
+}
+
+/*
+ * Some BUCKS supports Normal[ON/OFF] mode during suspend
+ *
+ * BUCK 1, 6, 2-4, 5, 7-10 (all)
+ *
+ * The other mode (0x02) will make PWRREQ switch between normal
+ * and low power.
+ */
+static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev)
+{
+	unsigned int val = MAX77802_OPMODE_STANDBY;
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int shift = max77802_get_opmode_shift(id);
+
+	max77802->opmode[id] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state
+ * (Enable Control Logic1 by PWRREQ)
+ *
+ * LDOs 2, 4-19, 22-35.
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
+						unsigned int mode)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	unsigned int val;
+	int shift = max77802_get_opmode_shift(id);
+
+	switch (mode) {
+	case REGULATOR_MODE_IDLE:			/* ON in LP Mode */
+		val = MAX77802_OPMODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:			/* ON in Normal Mode */
+		val = MAX77802_OPMODE_NORMAL;
+		break;
+	case REGULATOR_MODE_STANDBY:			/* ON/OFF by PWRREQ */
+		val = MAX77802_OPMODE_STANDBY;
+		break;
+	default:
+		dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+			 rdev->desc->name, mode);
+		return -EINVAL;
+	}
+
+	max77802->opmode[rdev_get_id(rdev)] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs
+ * (Enable Control Logic2 by PWRREQ)
+ *
+ * LDOs 1, 20, 21, and 3,
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev,
+						unsigned int mode)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	unsigned int val;
+	int shift = max77802_get_opmode_shift(id);
+
+	switch (mode) {
+	case REGULATOR_MODE_IDLE:			/* ON in LP Mode */
+		val = MAX77802_OPMODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:			/* ON in Normal Mode */
+		val = MAX77802_OPMODE_NORMAL;
+		break;
+	default:
+		dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+			 rdev->desc->name, mode);
+		return -EINVAL;
+	}
+
+	max77802->opmode[rdev_get_id(rdev)] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+static int max77802_enable(struct regulator_dev *rdev)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int shift = max77802_get_opmode_shift(id);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask,
+				  max77802->opmode[id] << shift);
+}
+
+static int max77802_find_ramp_value(struct regulator_dev *rdev,
+				    const unsigned int limits[], int size,
+				    unsigned int ramp_delay)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (ramp_delay <= limits[i])
+			return i;
+	}
+
+	/* Use maximum value for no ramp control */
+	dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n",
+		 rdev->desc->name, ramp_delay);
+	return size - 1;
+}
+
+/* Used for BUCKs 2-4 */
+static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev,
+					int ramp_delay)
+{
+	int id = rdev_get_id(rdev);
+	unsigned int ramp_value;
+
+	if (id > MAX77802_BUCK4) {
+			dev_warn(&rdev->dev,
+				 "%s: regulator: ramp delay not supported\n",
+				 rdev->desc->name);
+		return -EINVAL;
+	}
+	ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit,
+				ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  MAX77802_RAMP_RATE_MASK_2BIT,
+				  ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT);
+}
+
+/* For BUCK1, 6 */
+static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
+					    int ramp_delay)
+{
+	unsigned int ramp_value;
+
+	ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit,
+				ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  MAX77802_RAMP_RATE_MASK_4BIT,
+				  ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT);
+}
+
+/*
+ * LDOs 2, 4-19, 22-35
+ */
+static struct regulator_ops max77802_ldo_ops_logic1 = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_suspend_mode	= max77802_ldo_set_suspend_mode_logic1,
+};
+
+/*
+ * LDOs 1, 20, 21, 3
+ */
+static struct regulator_ops max77802_ldo_ops_logic2 = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_suspend_mode	= max77802_ldo_set_suspend_mode_logic2,
+};
+
+/* BUCKS 1, 6 */
+static struct regulator_ops max77802_buck_16_dvs_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_ramp_delay		= max77802_set_ramp_delay_4bit,
+	.set_suspend_disable	= max77802_buck_set_suspend_disable,
+};
+
+/* BUCKs 2-4, 5, 7-10 */
+static struct regulator_ops max77802_buck_dvs_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_ramp_delay		= max77802_set_ramp_delay_2bit,
+	.set_suspend_disable	= max77802_buck_set_suspend_disable,
+};
+
+/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */
+#define regulator_77802_desc_p_ldo(num, supply, log)	{		\
+	.name		= "LDO"#num,					\
+	.id		= MAX77802_LDO##num,				\
+	.supply_name	= "inl"#supply,					\
+	.ops		= &max77802_ldo_ops_logic##log,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 800000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */
+#define regulator_77802_desc_n_ldo(num, supply, log)   {		\
+	.name		= "LDO"#num,					\
+	.id		= MAX77802_LDO##num,				\
+	.supply_name	= "inl"#supply,					\
+	.ops		= &max77802_ldo_ops_logic##log,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 800000,					\
+	.uV_step	= 25000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* BUCKs 1, 6 */
+#define regulator_77802_desc_16_buck(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_16_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 612500,					\
+	.uV_step	= 6250,						\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 8,					\
+	.vsel_reg	= MAX77802_REG_BUCK ## num ## DVS1,		\
+	.vsel_mask	= MAX77802_DVS_VSEL_MASK,			\
+	.enable_reg	= MAX77802_REG_BUCK ## num ## CTRL,		\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+/* BUCKS 2-4 */
+#define regulator_77802_desc_234_buck(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 600000,					\
+	.uV_step	= 6250,						\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 0x91,						\
+	.vsel_reg	= MAX77802_REG_BUCK ## num ## DVS1,		\
+	.vsel_mask	= MAX77802_DVS_VSEL_MASK,			\
+	.enable_reg	= MAX77802_REG_BUCK ## num ## CTRL1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK <<			\
+				MAX77802_OPMODE_BUCK234_SHIFT,		\
+}
+
+/* BUCK 5 */
+#define regulator_77802_desc_buck5(num)		{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 750000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_BUCK5OUT,			\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_BUCK5CTRL,			\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+/* BUCKs 7-10 */
+#define regulator_77802_desc_buck7_10(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 750000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_BUCK7OUT + (num - 7) * 3,	\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_BUCK7CTRL + (num - 7) * 3,	\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_77802_desc_16_buck(1),
+	regulator_77802_desc_234_buck(2),
+	regulator_77802_desc_234_buck(3),
+	regulator_77802_desc_234_buck(4),
+	regulator_77802_desc_buck5(5),
+	regulator_77802_desc_16_buck(6),
+	regulator_77802_desc_buck7_10(7),
+	regulator_77802_desc_buck7_10(8),
+	regulator_77802_desc_buck7_10(9),
+	regulator_77802_desc_buck7_10(10),
+	regulator_77802_desc_n_ldo(1, 10, 2),
+	regulator_77802_desc_n_ldo(2, 10, 1),
+	regulator_77802_desc_p_ldo(3, 3, 2),
+	regulator_77802_desc_p_ldo(4, 6, 1),
+	regulator_77802_desc_p_ldo(5, 3, 1),
+	regulator_77802_desc_p_ldo(6, 3, 1),
+	regulator_77802_desc_p_ldo(7, 3, 1),
+	regulator_77802_desc_n_ldo(8, 1, 1),
+	regulator_77802_desc_p_ldo(9, 5, 1),
+	regulator_77802_desc_p_ldo(10, 4, 1),
+	regulator_77802_desc_p_ldo(11, 4, 1),
+	regulator_77802_desc_p_ldo(12, 9, 1),
+	regulator_77802_desc_p_ldo(13, 4, 1),
+	regulator_77802_desc_p_ldo(14, 4, 1),
+	regulator_77802_desc_n_ldo(15, 1, 1),
+	regulator_77802_desc_n_ldo(17, 2, 1),
+	regulator_77802_desc_p_ldo(18, 7, 1),
+	regulator_77802_desc_p_ldo(19, 5, 1),
+	regulator_77802_desc_p_ldo(20, 7, 2),
+	regulator_77802_desc_p_ldo(21, 6, 2),
+	regulator_77802_desc_p_ldo(23, 9, 1),
+	regulator_77802_desc_p_ldo(24, 6, 1),
+	regulator_77802_desc_p_ldo(25, 9, 1),
+	regulator_77802_desc_p_ldo(26, 9, 1),
+	regulator_77802_desc_n_ldo(27, 2, 1),
+	regulator_77802_desc_p_ldo(28, 7, 1),
+	regulator_77802_desc_p_ldo(29, 7, 1),
+	regulator_77802_desc_n_ldo(30, 2, 1),
+	regulator_77802_desc_p_ldo(32, 9, 1),
+	regulator_77802_desc_p_ldo(33, 6, 1),
+	regulator_77802_desc_p_ldo(34, 9, 1),
+	regulator_77802_desc_n_ldo(35, 2, 1),
+};
+
+#ifdef CONFIG_OF
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct max77802_platform_data *pdata)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct device_node *pmic_np, *regulators_np;
+	struct max77802_regulator_data *rdata;
+	struct of_regulator_match rmatch;
+	unsigned int i;
+
+	pmic_np = iodev->dev->of_node;
+	regulators_np = of_get_child_by_name(pmic_np, "regulators");
+	if (!regulators_np) {
+		dev_err(&pdev->dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	pdata->num_regulators = ARRAY_SIZE(regulators);
+	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+			     pdata->num_regulators, GFP_KERNEL);
+	if (!rdata) {
+		of_node_put(regulators_np);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		rmatch.name = regulators[i].name;
+		rmatch.init_data = NULL;
+		rmatch.of_node = NULL;
+		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
+				       1) != 1) {
+			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
+				 rmatch.name);
+			continue;
+		}
+		rdata[i].initdata = rmatch.init_data;
+		rdata[i].of_node = rmatch.of_node;
+		rdata[i].id = regulators[i].id;
+	}
+
+	pdata->regulators = rdata;
+	of_node_put(regulators_np);
+
+	return 0;
+}
+#else
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct max77802_platform_data *pdata)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
+/**
+ * max77802_setup_gpios - init DVS-related GPIOs
+ *
+ * This function claims / initalizations GPIOs related to DVS if they are
+ * defined. This may have the effect of switching voltages if the
+ * pdata->buck_default_idx does not match the boot time state of pins.
+ */
+static int max77802_setup_gpios(struct device *dev,
+				struct max77802_platform_data *pdata)
+{
+	int buck_default_idx = pdata->buck_default_idx;
+	int ret;
+	int i;
+
+	/* Set all SELB high to avoid glitching while DVS is changing */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_selb); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_selb[i];
+
+		/* OK if some GPIOs aren't defined */
+		if (IS_ERR(gpio))
+			continue;
+
+		ret = gpiod_direction_output_raw(gpio, 1);
+		if (ret) {
+			dev_err(dev, "can't set gpio[%d] dir: %d\n", i, ret);
+			return ret;
+		}
+	}
+
+	/* Set our initial setting */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_dvs); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_dvs[i];
+
+		/* OK if some GPIOs aren't defined */
+		if (IS_ERR(gpio))
+			continue;
+
+		/* If a GPIO is valid, set it */
+		gpiod_direction_output(gpio, (buck_default_idx >> i) & 1);
+		if (ret) {
+			dev_err(dev, "can't set gpio[%d]: dir %d\n", i, ret);
+			return ret;
+		}
+	}
+
+	/* Now set SELB low to take effect */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_selb); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_selb[i];
+
+		if (!IS_ERR(gpio))
+			gpiod_set_value(gpio, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * max77802_read_gpios - read the current state of the dvs GPIOs
+ *
+ * We call this function at bootup to detect what slot the firmware was
+ * using for the DVS GPIOs.  That way we can properly preserve the firmware's
+ * voltage settings
+ */
+static int max77802_read_gpios(struct max77802_platform_data *pdata)
+{
+	int buck_default_idx = pdata->buck_default_idx;
+	int result = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_dvs); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_dvs[i];
+
+		/* OK if some GPIOs aren't defined; we'll use default */
+		if (IS_ERR(gpio)) {
+			result |= buck_default_idx & (1 << i);
+			continue;
+		}
+
+		if (gpiod_get_value_cansleep(gpio))
+			result |= 1 << i;
+	}
+
+	return result;
+}
+
+static inline bool max77802_is_dvs_buck(int id)
+{
+	/* on 77802 bucks 1-4, 6 are */
+	return ((id >= MAX77802_BUCK1 && id <= MAX77802_BUCK4) ||
+		(id == MAX77802_BUCK6));
+}
+
+static int max77802_pmic_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max77802_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct max77802_regulator_prv *max77802;
+	int i, ret = 0, val;
+	struct regulator_config config = { };
+	unsigned int reg;
+	int buck_default_idx;
+	int buck_old_idx;
+
+	/* This is allocated by the MFD driver */
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data found for regulator\n");
+		return -ENODEV;
+	}
+
+	max77802 = devm_kzalloc(&pdev->dev,
+				sizeof(struct max77802_regulator_prv),
+				GFP_KERNEL);
+	if (!max77802)
+		return -ENOMEM;
+
+	if (iodev->dev->of_node) {
+		ret = max77802_pmic_dt_parse_pdata(pdev, pdata);
+		if (ret)
+			return ret;
+	}
+
+	config.dev = iodev->dev;
+	config.regmap = iodev->regmap;
+	config.driver_data = max77802;
+	platform_set_drvdata(pdev, max77802);
+
+	buck_default_idx = pdata->buck_default_idx;
+	buck_old_idx = max77802_read_gpios(pdata);
+
+	for (i = 0; i < MAX77802_REG_MAX; i++) {
+		struct regulator_dev *rdev;
+		int id = pdata->regulators[i].id;
+		int shift = max77802_get_opmode_shift(id);
+
+		config.init_data = pdata->regulators[i].initdata;
+		config.of_node = pdata->regulators[i].of_node;
+
+		ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val);
+		max77802->opmode[id] = val >> shift & MAX77802_OPMODE_MASK;
+
+		if (max77802_is_dvs_buck(id)) {
+			/* Try to copy over data so we keep firmware settings */
+			reg = regulators[i].vsel_reg;
+
+			ret = regmap_reg_copy(iodev->regmap,
+					      reg + buck_default_idx,
+					      reg + buck_old_idx);
+
+			if (ret)
+				dev_warn(&pdev->dev, "Copy err %d => %d (%d)\n",
+					 reg + buck_old_idx,
+					 reg + buck_default_idx, ret);
+
+			regulators[i].vsel_reg += buck_default_idx;
+		}
+
+		rdev = devm_regulator_register(&pdev->dev,
+					       &regulators[i], &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev,
+				"regulator init failed for %d\n", i);
+			return PTR_ERR(rdev);
+		}
+	}
+
+	ret = max77802_setup_gpios(&pdev->dev, pdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct platform_device_id max77802_pmic_id[] = {
+	{"max77802-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77802_pmic_id);
+
+static struct platform_driver max77802_pmic_driver = {
+	.driver = {
+		.name = "max77802-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max77802_pmic_probe,
+	.id_table = max77802_pmic_id,
+};
+
+module_platform_driver(max77802_pmic_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
-- 
2.0.0.rc2


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

* [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
(LDO) regulators. This patch adds support for all these regulators
found on the MAX77802 PMIC and is based on a driver added by Simon
Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Set the supply_name for regulators to lookup their parent supply node.
   Suggested by Mark Brown.
 - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
   Suggested by Doug Anderson.

Changes since v2:
 - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
 - Add a generic function to regmap core to copy registers instead of
   having a driver-specific function. Suggested by Mark Brown.
 - Remove unnecessary probe debug log. Suggested by Mark Brown.
 - Set struct regulator_config dev field to MFD instead of the platform dev.
   Suggested by Mark Brown.
 - Read the regulators operational mode from the hardware registers instead
   of setting to normal as default on probe. Suggested by Mark Brown.
 - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.

Changes since v1:
 - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
 - Fix .set_suspend_mode handler comment and split regulators ops for
   regulators that behave differently. Suggested by Mark Brown.
 - Use module_platform_driver() instead of having init/exit functions.
   Suggested by Mark Brown.
 - Use the new descriptor-based GPIO interface instead of the deprecated
   integer based GPIO one. Suggested by Mark Brown.
 - Look for "regulators" child node instead of "voltage-regulators" to be
   consistent with other PMIC drivers. Suggested by Mark Brown.

 drivers/regulator/Kconfig    |   9 +
 drivers/regulator/Makefile   |   1 +
 drivers/regulator/max77802.c | 694 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 704 insertions(+)
 create mode 100644 drivers/regulator/max77802.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 789eb46..283f172 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -377,6 +377,15 @@ config REGULATOR_MAX77693
 	  and one current regulator 'CHARGER'. This is suitable for
 	  Exynos-4x12 chips.
 
+config REGULATOR_MAX77802
+	tristate "Maxim 77802 regulator"
+	depends on MFD_MAX77802
+	help
+	  This driver controls a Maxim 77802 regulator
+	  via I2C bus. The provided regulator is suitable for
+	  Exynos5420/Exynos5800 SoCs to control various voltages.
+	  It includes support for control of voltage and ramp speed.
+
 config REGULATOR_MC13XXX_CORE
 	tristate
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d461110..2aea4b6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
+obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c
new file mode 100644
index 0000000..8fd70b6
--- /dev/null
+++ b/drivers/regulator/max77802.c
@@ -0,0 +1,694 @@
+/*
+ * max77802.c - Regulator driver for the Maxim 77802
+ *
+ * Copyright (C) 2013-2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+
+/* Default ramp delay in case it is not manually set */
+#define MAX77802_RAMP_DELAY		100000		/* uV/us */
+
+#define MAX77802_OPMODE_SHIFT_LDO	6
+#define MAX77802_OPMODE_BUCK234_SHIFT	4
+#define MAX77802_OPMODE_MASK		0x3
+
+#define MAX77802_VSEL_MASK		0x3F
+#define MAX77802_DVS_VSEL_MASK		0xFF
+
+#define MAX77802_RAMP_RATE_MASK_2BIT	0xC0
+#define MAX77802_RAMP_RATE_SHIFT_2BIT	6
+#define MAX77802_RAMP_RATE_MASK_4BIT	0xF0
+#define MAX77802_RAMP_RATE_SHIFT_4BIT	4
+
+/* MAX77802 has two register formats: 2-bit and 4-bit */
+static const unsigned int ramp_table_77802_2bit[] = {
+	12500,
+	25000,
+	50000,
+	100000,
+};
+
+static unsigned int ramp_table_77802_4bit[] = {
+	1000,	2000,	3030,	4000,
+	5000,	5880,	7140,	8330,
+	9090,	10000,	11110,	12500,
+	16670,	25000,	50000,	100000,
+};
+
+struct max77802_regulator_prv {
+	int num_regulators;
+	struct regulator_dev *rdev[MAX77802_REG_MAX];
+	unsigned int opmode[MAX77802_REG_MAX];
+};
+
+static int max77802_get_opmode_shift(int id)
+{
+	if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35)
+		return MAX77802_OPMODE_SHIFT_LDO;
+	else if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 &&
+					  id <= MAX77802_BUCK10))
+		return 0;
+	else if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4)
+		return MAX77802_OPMODE_BUCK234_SHIFT;
+	else
+		return -EINVAL;
+}
+
+/*
+ * Some BUCKS supports Normal[ON/OFF] mode during suspend
+ *
+ * BUCK 1, 6, 2-4, 5, 7-10 (all)
+ *
+ * The other mode (0x02) will make PWRREQ switch between normal
+ * and low power.
+ */
+static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev)
+{
+	unsigned int val = MAX77802_OPMODE_STANDBY;
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int shift = max77802_get_opmode_shift(id);
+
+	max77802->opmode[id] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state
+ * (Enable Control Logic1 by PWRREQ)
+ *
+ * LDOs 2, 4-19, 22-35.
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
+						unsigned int mode)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	unsigned int val;
+	int shift = max77802_get_opmode_shift(id);
+
+	switch (mode) {
+	case REGULATOR_MODE_IDLE:			/* ON in LP Mode */
+		val = MAX77802_OPMODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:			/* ON in Normal Mode */
+		val = MAX77802_OPMODE_NORMAL;
+		break;
+	case REGULATOR_MODE_STANDBY:			/* ON/OFF by PWRREQ */
+		val = MAX77802_OPMODE_STANDBY;
+		break;
+	default:
+		dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+			 rdev->desc->name, mode);
+		return -EINVAL;
+	}
+
+	max77802->opmode[rdev_get_id(rdev)] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs
+ * (Enable Control Logic2 by PWRREQ)
+ *
+ * LDOs 1, 20, 21, and 3,
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev,
+						unsigned int mode)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	unsigned int val;
+	int shift = max77802_get_opmode_shift(id);
+
+	switch (mode) {
+	case REGULATOR_MODE_IDLE:			/* ON in LP Mode */
+		val = MAX77802_OPMODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:			/* ON in Normal Mode */
+		val = MAX77802_OPMODE_NORMAL;
+		break;
+	default:
+		dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+			 rdev->desc->name, mode);
+		return -EINVAL;
+	}
+
+	max77802->opmode[rdev_get_id(rdev)] = val;
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val << shift);
+}
+
+static int max77802_enable(struct regulator_dev *rdev)
+{
+	struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int shift = max77802_get_opmode_shift(id);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask,
+				  max77802->opmode[id] << shift);
+}
+
+static int max77802_find_ramp_value(struct regulator_dev *rdev,
+				    const unsigned int limits[], int size,
+				    unsigned int ramp_delay)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (ramp_delay <= limits[i])
+			return i;
+	}
+
+	/* Use maximum value for no ramp control */
+	dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n",
+		 rdev->desc->name, ramp_delay);
+	return size - 1;
+}
+
+/* Used for BUCKs 2-4 */
+static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev,
+					int ramp_delay)
+{
+	int id = rdev_get_id(rdev);
+	unsigned int ramp_value;
+
+	if (id > MAX77802_BUCK4) {
+			dev_warn(&rdev->dev,
+				 "%s: regulator: ramp delay not supported\n",
+				 rdev->desc->name);
+		return -EINVAL;
+	}
+	ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit,
+				ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  MAX77802_RAMP_RATE_MASK_2BIT,
+				  ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT);
+}
+
+/* For BUCK1, 6 */
+static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
+					    int ramp_delay)
+{
+	unsigned int ramp_value;
+
+	ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit,
+				ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  MAX77802_RAMP_RATE_MASK_4BIT,
+				  ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT);
+}
+
+/*
+ * LDOs 2, 4-19, 22-35
+ */
+static struct regulator_ops max77802_ldo_ops_logic1 = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_suspend_mode	= max77802_ldo_set_suspend_mode_logic1,
+};
+
+/*
+ * LDOs 1, 20, 21, 3
+ */
+static struct regulator_ops max77802_ldo_ops_logic2 = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_suspend_mode	= max77802_ldo_set_suspend_mode_logic2,
+};
+
+/* BUCKS 1, 6 */
+static struct regulator_ops max77802_buck_16_dvs_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_ramp_delay		= max77802_set_ramp_delay_4bit,
+	.set_suspend_disable	= max77802_buck_set_suspend_disable,
+};
+
+/* BUCKs 2-4, 5, 7-10 */
+static struct regulator_ops max77802_buck_dvs_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= max77802_enable,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_ramp_delay		= max77802_set_ramp_delay_2bit,
+	.set_suspend_disable	= max77802_buck_set_suspend_disable,
+};
+
+/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */
+#define regulator_77802_desc_p_ldo(num, supply, log)	{		\
+	.name		= "LDO"#num,					\
+	.id		= MAX77802_LDO##num,				\
+	.supply_name	= "inl"#supply,					\
+	.ops		= &max77802_ldo_ops_logic##log,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 800000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */
+#define regulator_77802_desc_n_ldo(num, supply, log)   {		\
+	.name		= "LDO"#num,					\
+	.id		= MAX77802_LDO##num,				\
+	.supply_name	= "inl"#supply,					\
+	.ops		= &max77802_ldo_ops_logic##log,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 800000,					\
+	.uV_step	= 25000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_LDO1CTRL1 + num - 1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* BUCKs 1, 6 */
+#define regulator_77802_desc_16_buck(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_16_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 612500,					\
+	.uV_step	= 6250,						\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 8,					\
+	.vsel_reg	= MAX77802_REG_BUCK ## num ## DVS1,		\
+	.vsel_mask	= MAX77802_DVS_VSEL_MASK,			\
+	.enable_reg	= MAX77802_REG_BUCK ## num ## CTRL,		\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+/* BUCKS 2-4 */
+#define regulator_77802_desc_234_buck(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 600000,					\
+	.uV_step	= 6250,						\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 0x91,						\
+	.vsel_reg	= MAX77802_REG_BUCK ## num ## DVS1,		\
+	.vsel_mask	= MAX77802_DVS_VSEL_MASK,			\
+	.enable_reg	= MAX77802_REG_BUCK ## num ## CTRL1,		\
+	.enable_mask	= MAX77802_OPMODE_MASK <<			\
+				MAX77802_OPMODE_BUCK234_SHIFT,		\
+}
+
+/* BUCK 5 */
+#define regulator_77802_desc_buck5(num)		{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 750000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_BUCK5OUT,			\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_BUCK5CTRL,			\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+/* BUCKs 7-10 */
+#define regulator_77802_desc_buck7_10(num)	{		\
+	.name		= "BUCK"#num,					\
+	.id		= MAX77802_BUCK##num,				\
+	.supply_name	= "inb"#num,					\
+	.ops		= &max77802_buck_dvs_ops,			\
+	.type		= REGULATOR_VOLTAGE,				\
+	.owner		= THIS_MODULE,					\
+	.min_uV		= 750000,					\
+	.uV_step	= 50000,					\
+	.ramp_delay	= MAX77802_RAMP_DELAY,				\
+	.n_voltages	= 1 << 6,					\
+	.vsel_reg	= MAX77802_REG_BUCK7OUT + (num - 7) * 3,	\
+	.vsel_mask	= MAX77802_VSEL_MASK,				\
+	.enable_reg	= MAX77802_REG_BUCK7CTRL + (num - 7) * 3,	\
+	.enable_mask	= MAX77802_OPMODE_MASK,				\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_77802_desc_16_buck(1),
+	regulator_77802_desc_234_buck(2),
+	regulator_77802_desc_234_buck(3),
+	regulator_77802_desc_234_buck(4),
+	regulator_77802_desc_buck5(5),
+	regulator_77802_desc_16_buck(6),
+	regulator_77802_desc_buck7_10(7),
+	regulator_77802_desc_buck7_10(8),
+	regulator_77802_desc_buck7_10(9),
+	regulator_77802_desc_buck7_10(10),
+	regulator_77802_desc_n_ldo(1, 10, 2),
+	regulator_77802_desc_n_ldo(2, 10, 1),
+	regulator_77802_desc_p_ldo(3, 3, 2),
+	regulator_77802_desc_p_ldo(4, 6, 1),
+	regulator_77802_desc_p_ldo(5, 3, 1),
+	regulator_77802_desc_p_ldo(6, 3, 1),
+	regulator_77802_desc_p_ldo(7, 3, 1),
+	regulator_77802_desc_n_ldo(8, 1, 1),
+	regulator_77802_desc_p_ldo(9, 5, 1),
+	regulator_77802_desc_p_ldo(10, 4, 1),
+	regulator_77802_desc_p_ldo(11, 4, 1),
+	regulator_77802_desc_p_ldo(12, 9, 1),
+	regulator_77802_desc_p_ldo(13, 4, 1),
+	regulator_77802_desc_p_ldo(14, 4, 1),
+	regulator_77802_desc_n_ldo(15, 1, 1),
+	regulator_77802_desc_n_ldo(17, 2, 1),
+	regulator_77802_desc_p_ldo(18, 7, 1),
+	regulator_77802_desc_p_ldo(19, 5, 1),
+	regulator_77802_desc_p_ldo(20, 7, 2),
+	regulator_77802_desc_p_ldo(21, 6, 2),
+	regulator_77802_desc_p_ldo(23, 9, 1),
+	regulator_77802_desc_p_ldo(24, 6, 1),
+	regulator_77802_desc_p_ldo(25, 9, 1),
+	regulator_77802_desc_p_ldo(26, 9, 1),
+	regulator_77802_desc_n_ldo(27, 2, 1),
+	regulator_77802_desc_p_ldo(28, 7, 1),
+	regulator_77802_desc_p_ldo(29, 7, 1),
+	regulator_77802_desc_n_ldo(30, 2, 1),
+	regulator_77802_desc_p_ldo(32, 9, 1),
+	regulator_77802_desc_p_ldo(33, 6, 1),
+	regulator_77802_desc_p_ldo(34, 9, 1),
+	regulator_77802_desc_n_ldo(35, 2, 1),
+};
+
+#ifdef CONFIG_OF
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct max77802_platform_data *pdata)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct device_node *pmic_np, *regulators_np;
+	struct max77802_regulator_data *rdata;
+	struct of_regulator_match rmatch;
+	unsigned int i;
+
+	pmic_np = iodev->dev->of_node;
+	regulators_np = of_get_child_by_name(pmic_np, "regulators");
+	if (!regulators_np) {
+		dev_err(&pdev->dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	pdata->num_regulators = ARRAY_SIZE(regulators);
+	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+			     pdata->num_regulators, GFP_KERNEL);
+	if (!rdata) {
+		of_node_put(regulators_np);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		rmatch.name = regulators[i].name;
+		rmatch.init_data = NULL;
+		rmatch.of_node = NULL;
+		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
+				       1) != 1) {
+			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
+				 rmatch.name);
+			continue;
+		}
+		rdata[i].initdata = rmatch.init_data;
+		rdata[i].of_node = rmatch.of_node;
+		rdata[i].id = regulators[i].id;
+	}
+
+	pdata->regulators = rdata;
+	of_node_put(regulators_np);
+
+	return 0;
+}
+#else
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct max77802_platform_data *pdata)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
+/**
+ * max77802_setup_gpios - init DVS-related GPIOs
+ *
+ * This function claims / initalizations GPIOs related to DVS if they are
+ * defined. This may have the effect of switching voltages if the
+ * pdata->buck_default_idx does not match the boot time state of pins.
+ */
+static int max77802_setup_gpios(struct device *dev,
+				struct max77802_platform_data *pdata)
+{
+	int buck_default_idx = pdata->buck_default_idx;
+	int ret;
+	int i;
+
+	/* Set all SELB high to avoid glitching while DVS is changing */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_selb); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_selb[i];
+
+		/* OK if some GPIOs aren't defined */
+		if (IS_ERR(gpio))
+			continue;
+
+		ret = gpiod_direction_output_raw(gpio, 1);
+		if (ret) {
+			dev_err(dev, "can't set gpio[%d] dir: %d\n", i, ret);
+			return ret;
+		}
+	}
+
+	/* Set our initial setting */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_dvs); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_dvs[i];
+
+		/* OK if some GPIOs aren't defined */
+		if (IS_ERR(gpio))
+			continue;
+
+		/* If a GPIO is valid, set it */
+		gpiod_direction_output(gpio, (buck_default_idx >> i) & 1);
+		if (ret) {
+			dev_err(dev, "can't set gpio[%d]: dir %d\n", i, ret);
+			return ret;
+		}
+	}
+
+	/* Now set SELB low to take effect */
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_selb); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_selb[i];
+
+		if (!IS_ERR(gpio))
+			gpiod_set_value(gpio, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * max77802_read_gpios - read the current state of the dvs GPIOs
+ *
+ * We call this function at bootup to detect what slot the firmware was
+ * using for the DVS GPIOs.  That way we can properly preserve the firmware's
+ * voltage settings
+ */
+static int max77802_read_gpios(struct max77802_platform_data *pdata)
+{
+	int buck_default_idx = pdata->buck_default_idx;
+	int result = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_dvs); i++) {
+		struct gpio_desc *gpio = pdata->buck_gpio_dvs[i];
+
+		/* OK if some GPIOs aren't defined; we'll use default */
+		if (IS_ERR(gpio)) {
+			result |= buck_default_idx & (1 << i);
+			continue;
+		}
+
+		if (gpiod_get_value_cansleep(gpio))
+			result |= 1 << i;
+	}
+
+	return result;
+}
+
+static inline bool max77802_is_dvs_buck(int id)
+{
+	/* on 77802 bucks 1-4, 6 are */
+	return ((id >= MAX77802_BUCK1 && id <= MAX77802_BUCK4) ||
+		(id == MAX77802_BUCK6));
+}
+
+static int max77802_pmic_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max77802_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct max77802_regulator_prv *max77802;
+	int i, ret = 0, val;
+	struct regulator_config config = { };
+	unsigned int reg;
+	int buck_default_idx;
+	int buck_old_idx;
+
+	/* This is allocated by the MFD driver */
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data found for regulator\n");
+		return -ENODEV;
+	}
+
+	max77802 = devm_kzalloc(&pdev->dev,
+				sizeof(struct max77802_regulator_prv),
+				GFP_KERNEL);
+	if (!max77802)
+		return -ENOMEM;
+
+	if (iodev->dev->of_node) {
+		ret = max77802_pmic_dt_parse_pdata(pdev, pdata);
+		if (ret)
+			return ret;
+	}
+
+	config.dev = iodev->dev;
+	config.regmap = iodev->regmap;
+	config.driver_data = max77802;
+	platform_set_drvdata(pdev, max77802);
+
+	buck_default_idx = pdata->buck_default_idx;
+	buck_old_idx = max77802_read_gpios(pdata);
+
+	for (i = 0; i < MAX77802_REG_MAX; i++) {
+		struct regulator_dev *rdev;
+		int id = pdata->regulators[i].id;
+		int shift = max77802_get_opmode_shift(id);
+
+		config.init_data = pdata->regulators[i].initdata;
+		config.of_node = pdata->regulators[i].of_node;
+
+		ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val);
+		max77802->opmode[id] = val >> shift & MAX77802_OPMODE_MASK;
+
+		if (max77802_is_dvs_buck(id)) {
+			/* Try to copy over data so we keep firmware settings */
+			reg = regulators[i].vsel_reg;
+
+			ret = regmap_reg_copy(iodev->regmap,
+					      reg + buck_default_idx,
+					      reg + buck_old_idx);
+
+			if (ret)
+				dev_warn(&pdev->dev, "Copy err %d => %d (%d)\n",
+					 reg + buck_old_idx,
+					 reg + buck_default_idx, ret);
+
+			regulators[i].vsel_reg += buck_default_idx;
+		}
+
+		rdev = devm_regulator_register(&pdev->dev,
+					       &regulators[i], &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev,
+				"regulator init failed for %d\n", i);
+			return PTR_ERR(rdev);
+		}
+	}
+
+	ret = max77802_setup_gpios(&pdev->dev, pdata);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct platform_device_id max77802_pmic_id[] = {
+	{"max77802-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77802_pmic_id);
+
+static struct platform_driver max77802_pmic_driver = {
+	.driver = {
+		.name = "max77802-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max77802_pmic_probe,
+	.id_table = max77802_pmic_id,
+};
+
+module_platform_driver(max77802_pmic_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
-- 
2.0.0.rc2

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

* [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

The MAX77802 PMIC has two 32.768kHz Buffered Clock Outputs with
Low Jitter Mode. This patch adds support for these two clocks.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

Changes since v2: None

Changes since v1:
 - Use module_platform_driver() instead of having init/exit functions.
   Suggested by Mark Brown.
 - Use the generic maxim clock driver to reduce code duplication with
   clk-max77686.c driver.

 drivers/clk/Kconfig                        |  7 +++
 drivers/clk/Makefile                       |  1 +
 drivers/clk/clk-max77802.c                 | 99 ++++++++++++++++++++++++++++++
 include/dt-bindings/clock/maxim,max77802.h | 22 +++++++
 4 files changed, 129 insertions(+)
 create mode 100644 drivers/clk/clk-max77802.c
 create mode 100644 include/dt-bindings/clock/maxim,max77802.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3fd4270..221260b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,6 +42,13 @@ config COMMON_CLK_MAX77686
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
+config COMMON_CLK_MAX77802
+	tristate "Clock driver for Maxim 77802 MFD"
+	depends on MFD_MAX77802
+	select COMMON_CLK_MAX_GEN
+	---help---
+	  This driver supports Maxim 77802 crystal oscillator clock.
+
 config COMMON_CLK_SI5351
 	tristate "Clock driver for SiLabs 5351A/B/C"
 	depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 6c1aff6..520ff76 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
+obj-$(CONFIG_COMMON_CLK_MAX77802)	+= clk-max77802.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
new file mode 100644
index 0000000..4253b44
--- /dev/null
+++ b/drivers/clk/clk-max77802.c
@@ -0,0 +1,99 @@
+/*
+ * clk-max77802.c - Clock driver for Maxim 77802
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+#include <dt-bindings/clock/maxim,max77802.h>
+#include "clk-max-gen.h"
+
+#define MAX77802_CLOCK_OPMODE_MASK	0x1
+#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
+
+static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
+	[MAX77802_CLK_32K_AP] = {
+		.name = "32khz_ap",
+		.ops = &max_gen_clk_ops,
+		.flags = CLK_IS_ROOT,
+	},
+	[MAX77802_CLK_32K_CP] = {
+		.name = "32khz_cp",
+		.ops = &max_gen_clk_ops,
+		.flags = CLK_IS_ROOT,
+	},
+};
+
+static int max77802_clk_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	int ret;
+
+	ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
+				max77802_clks_init, MAX77802_CLKS_NUM);
+
+	if (ret) {
+		dev_err(&pdev->dev, "generic probe failed %d\n", ret);
+		return ret;
+	}
+
+	/* Enable low-jitter mode on the 32khz clocks. */
+	ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
+				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
+				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
+	if (ret < 0)
+		dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
+
+	return ret;
+}
+
+static int max77802_clk_remove(struct platform_device *pdev)
+{
+	return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
+}
+
+static const struct platform_device_id max77802_clk_id[] = {
+	{ "max77802-clk", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77802_clk_id);
+
+static struct platform_driver max77802_clk_driver = {
+	.driver = {
+		.name  = "max77802-clk",
+		.owner = THIS_MODULE,
+	},
+	.probe = max77802_clk_probe,
+	.remove = max77802_clk_remove,
+	.id_table = max77802_clk_id,
+};
+
+module_platform_driver(max77802_clk_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
+MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
new file mode 100644
index 0000000..997312e
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77802.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77802 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77802_CLK_32K_AP		0
+#define MAX77802_CLK_32K_CP		1
+
+/* Total number of clocks. */
+#define MAX77802_CLKS_NUM		(MAX77802_CLK_32K_CP + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */
-- 
2.0.0.rc2


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

* [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

The MAX77802 PMIC has two 32.768kHz Buffered Clock Outputs with
Low Jitter Mode. This patch adds support for these two clocks.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

Changes since v2: None

Changes since v1:
 - Use module_platform_driver() instead of having init/exit functions.
   Suggested by Mark Brown.
 - Use the generic maxim clock driver to reduce code duplication with
   clk-max77686.c driver.

 drivers/clk/Kconfig                        |  7 +++
 drivers/clk/Makefile                       |  1 +
 drivers/clk/clk-max77802.c                 | 99 ++++++++++++++++++++++++++++++
 include/dt-bindings/clock/maxim,max77802.h | 22 +++++++
 4 files changed, 129 insertions(+)
 create mode 100644 drivers/clk/clk-max77802.c
 create mode 100644 include/dt-bindings/clock/maxim,max77802.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3fd4270..221260b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,6 +42,13 @@ config COMMON_CLK_MAX77686
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
+config COMMON_CLK_MAX77802
+	tristate "Clock driver for Maxim 77802 MFD"
+	depends on MFD_MAX77802
+	select COMMON_CLK_MAX_GEN
+	---help---
+	  This driver supports Maxim 77802 crystal oscillator clock.
+
 config COMMON_CLK_SI5351
 	tristate "Clock driver for SiLabs 5351A/B/C"
 	depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 6c1aff6..520ff76 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
+obj-$(CONFIG_COMMON_CLK_MAX77802)	+= clk-max77802.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
new file mode 100644
index 0000000..4253b44
--- /dev/null
+++ b/drivers/clk/clk-max77802.c
@@ -0,0 +1,99 @@
+/*
+ * clk-max77802.c - Clock driver for Maxim 77802
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77802.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+#include <dt-bindings/clock/maxim,max77802.h>
+#include "clk-max-gen.h"
+
+#define MAX77802_CLOCK_OPMODE_MASK	0x1
+#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
+
+static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
+	[MAX77802_CLK_32K_AP] = {
+		.name = "32khz_ap",
+		.ops = &max_gen_clk_ops,
+		.flags = CLK_IS_ROOT,
+	},
+	[MAX77802_CLK_32K_CP] = {
+		.name = "32khz_cp",
+		.ops = &max_gen_clk_ops,
+		.flags = CLK_IS_ROOT,
+	},
+};
+
+static int max77802_clk_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	int ret;
+
+	ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
+				max77802_clks_init, MAX77802_CLKS_NUM);
+
+	if (ret) {
+		dev_err(&pdev->dev, "generic probe failed %d\n", ret);
+		return ret;
+	}
+
+	/* Enable low-jitter mode on the 32khz clocks. */
+	ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
+				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
+				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
+	if (ret < 0)
+		dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
+
+	return ret;
+}
+
+static int max77802_clk_remove(struct platform_device *pdev)
+{
+	return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
+}
+
+static const struct platform_device_id max77802_clk_id[] = {
+	{ "max77802-clk", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77802_clk_id);
+
+static struct platform_driver max77802_clk_driver = {
+	.driver = {
+		.name  = "max77802-clk",
+		.owner = THIS_MODULE,
+	},
+	.probe = max77802_clk_probe,
+	.remove = max77802_clk_remove,
+	.id_table = max77802_clk_id,
+};
+
+module_platform_driver(max77802_clk_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
+MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
new file mode 100644
index 0000000..997312e
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77802.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77802 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77802_CLK_32K_AP		0
+#define MAX77802_CLK_32K_CP		1
+
+/* Total number of clocks. */
+#define MAX77802_CLKS_NUM		(MAX77802_CLK_32K_CP + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */
-- 
2.0.0.rc2

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

* [PATCH v4 12/14] clk: max77802: Add DT binding documentation
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Add Device Tree binding documentation for the clocks
outputs in the Maxim 77802 Power Management IC.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Don't use the same clock driver name in clock-names since it's a consumer
   concept and most probably will be different. Suggested by Doug Anderson.

Changes since v2:
 - Split the DT binding documentation in a separate patch.

 .../devicetree/bindings/clock/maxim,max77802.txt   | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt

diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
new file mode 100644
index 0000000..26bc4f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
@@ -0,0 +1,42 @@
+Binding for Maxim MAX77802 32k clock generator block
+
+This is a part of device tree bindings of MAX77802 multi-function device.
+More information can be found in bindings/mfd/max77802.txt file.
+
+The MAX77802 contains two 32.768khz clock outputs that can be controlled
+(gated/ungated) over I2C.
+
+Following properties should be presend in main device node of the MFD chip.
+
+Required properties:
+
+- #clock-cells: from common clock binding; shall be set to 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
+     - 0: 32khz_ap clock,
+     - 1: 32khz_cp clock.
+
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h
+header and can be used in device tree sources.
+
+Example: Node of the MFD chip
+
+	max77802: max77802@09 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&wakeup_eint>;
+		interrupts = <26 0>;
+		reg = <0x09>;
+		#clock-cells = <1>;
+
+		/* ... */
+	};
+
+Example: Clock consumer node
+
+	foo@0 {
+		compatible = "bar,foo";
+		/* ... */
+		clock-names = "my-clock";
+		clocks = <&max77802 MAX77802_CLK_32K_AP>;
+	};
-- 
2.0.0.rc2


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

* [PATCH v4 12/14] clk: max77802: Add DT binding documentation
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Add Device Tree binding documentation for the clocks
outputs in the Maxim 77802 Power Management IC.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Don't use the same clock driver name in clock-names since it's a consumer
   concept and most probably will be different. Suggested by Doug Anderson.

Changes since v2:
 - Split the DT binding documentation in a separate patch.

 .../devicetree/bindings/clock/maxim,max77802.txt   | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt

diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
new file mode 100644
index 0000000..26bc4f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
@@ -0,0 +1,42 @@
+Binding for Maxim MAX77802 32k clock generator block
+
+This is a part of device tree bindings of MAX77802 multi-function device.
+More information can be found in bindings/mfd/max77802.txt file.
+
+The MAX77802 contains two 32.768khz clock outputs that can be controlled
+(gated/ungated) over I2C.
+
+Following properties should be presend in main device node of the MFD chip.
+
+Required properties:
+
+- #clock-cells: from common clock binding; shall be set to 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
+     - 0: 32khz_ap clock,
+     - 1: 32khz_cp clock.
+
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h
+header and can be used in device tree sources.
+
+Example: Node of the MFD chip
+
+	max77802: max77802 at 09 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&wakeup_eint>;
+		interrupts = <26 0>;
+		reg = <0x09>;
+		#clock-cells = <1>;
+
+		/* ... */
+	};
+
+Example: Clock consumer node
+
+	foo at 0 {
+		compatible = "bar,foo";
+		/* ... */
+		clock-names = "my-clock";
+		clocks = <&max77802 MAX77802_CLK_32K_AP>;
+	};
-- 
2.0.0.rc2

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

* [PATCH v4 13/14] rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

The MAX7802 PMIC has a Real-Time-Clock (RTC) with two alarms.
This patch adds support for the RTC and is based on a driver
added by Simon Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

 drivers/rtc/Kconfig        |  10 +
 drivers/rtc/Makefile       |   1 +
 drivers/rtc/rtc-max77802.c | 637 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 648 insertions(+)
 create mode 100644 drivers/rtc/rtc-max77802.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0754f5c..e0b6495 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -288,6 +288,16 @@ config RTC_DRV_MAX77686
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-max77686.
 
+config RTC_DRV_MAX77802
+	tristate "Maxim MAX77802"
+	depends on MFD_MAX77802
+	help
+	  If you say yes here you will get support for the
+	  RTC of Maxim MAX77802 PMIC.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max77802.
+
 config RTC_DRV_RS5C372
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 70347d0..247de78 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_RTC_DRV_MAX8998)	+= rtc-max8998.o
 obj-$(CONFIG_RTC_DRV_MAX8997)	+= rtc-max8997.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MAX77686)	+= rtc-max77686.o
+obj-$(CONFIG_RTC_DRV_MAX77802)  += rtc-max77802.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MCP795)	+= rtc-mcp795.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c
new file mode 100644
index 0000000..7e5d031
--- /dev/null
+++ b/drivers/rtc/rtc-max77802.c
@@ -0,0 +1,637 @@
+/*
+ * RTC driver for Maxim MAX77802
+ *
+ * Copyright (C) 2013 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *
+ *  based on rtc-max8997.c
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT			0
+#define BCD_EN_MASK			(1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT			1
+#define MODEL24_MASK			(1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT			0
+#define RTC_UDR_MASK			(1 << RTC_UDR_SHIFT)
+#define RTC_RBUDR_SHIFT			4
+#define RTC_RBUDR_MASK			(1 << RTC_RBUDR_SHIFT)
+/* WTSR and SMPL Register */
+#define WTSRT_SHIFT			0
+#define SMPLT_SHIFT			2
+#define WTSR_EN_SHIFT			6
+#define SMPL_EN_SHIFT			7
+#define WTSRT_MASK			(3 << WTSRT_SHIFT)
+#define SMPLT_MASK			(3 << SMPLT_SHIFT)
+#define WTSR_EN_MASK			(1 << WTSR_EN_SHIFT)
+#define SMPL_EN_MASK			(1 << SMPL_EN_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT			6
+#define HOUR_PM_MASK			(1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT		7
+#define ALARM_ENABLE_MASK		(1 << ALARM_ENABLE_SHIFT)
+
+/* For the RTCAE1 register, we write this value to enable the alarm */
+#define ALARM_ENABLE_VALUE		0x77
+
+#define MAX77802_RTC_UPDATE_DELAY_US	200
+#undef MAX77802_RTC_WTSR_SMPL
+
+enum {
+	RTC_SEC = 0,
+	RTC_MIN,
+	RTC_HOUR,
+	RTC_WEEKDAY,
+	RTC_MONTH,
+	RTC_YEAR,
+	RTC_DATE,
+	RTC_NR_TIME
+};
+
+struct max77802_rtc_info {
+	struct device		*dev;
+	struct max77802_dev	*max77802;
+	struct i2c_client	*rtc;
+	struct rtc_device	*rtc_dev;
+	struct mutex		lock;
+
+	struct regmap		*regmap;
+
+	int virq;
+	int rtc_24hr_mode;
+};
+
+enum MAX77802_RTC_OP {
+	MAX77802_RTC_WRITE,
+	MAX77802_RTC_READ,
+};
+
+static inline int max77802_rtc_calculate_wday(u8 shifted)
+{
+	int counter = -1;
+
+	while (shifted) {
+		shifted >>= 1;
+		counter++;
+	}
+
+	return counter;
+}
+
+static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
+				   int rtc_24hr_mode)
+{
+	tm->tm_sec = data[RTC_SEC] & 0xff;
+	tm->tm_min = data[RTC_MIN] & 0xff;
+	if (rtc_24hr_mode)
+		tm->tm_hour = data[RTC_HOUR] & 0x1f;
+	else {
+		tm->tm_hour = data[RTC_HOUR] & 0x0f;
+		if (data[RTC_HOUR] & HOUR_PM_MASK)
+			tm->tm_hour += 12;
+	}
+
+	tm->tm_wday = max77802_rtc_calculate_wday(data[RTC_WEEKDAY] & 0xff);
+	tm->tm_mday = data[RTC_DATE] & 0x1f;
+	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
+
+	tm->tm_year = data[RTC_YEAR] & 0xff;
+	tm->tm_yday = 0;
+	tm->tm_isdst = 0;
+}
+
+static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+	data[RTC_SEC] = tm->tm_sec;
+	data[RTC_MIN] = tm->tm_min;
+	data[RTC_HOUR] = tm->tm_hour;
+	data[RTC_WEEKDAY] = 1 << tm->tm_wday;
+	data[RTC_DATE] = tm->tm_mday;
+	data[RTC_MONTH] = tm->tm_mon + 1;
+	data[RTC_YEAR] = tm->tm_year;
+
+	return 0;
+}
+
+static int max77802_rtc_update(struct max77802_rtc_info *info,
+	enum MAX77802_RTC_OP op)
+{
+	int ret;
+	unsigned int data;
+
+	if (op == MAX77802_RTC_WRITE)
+		data = 1 << RTC_UDR_SHIFT;
+	else
+		data = 1 << RTC_RBUDR_SHIFT;
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_RTC_UPDATE0, data, data);
+	if (ret < 0)
+		dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
+				__func__, ret, data);
+	else {
+		/* Minimum delay required before RTC update. */
+		usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
+			     MAX77802_RTC_UPDATE_DELAY_US * 2);
+	}
+
+	return ret;
+}
+
+static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_read(info->max77802->regmap,
+				MAX77802_RTC_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
+			ret);
+		goto out;
+	}
+
+	max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+
+	ret = rtc_valid_tm(tm);
+
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	ret = max77802_rtc_tm_to_data(tm, data);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&info->lock);
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				 MAX77802_RTC_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
+			ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_read(info->max77802->regmap,
+				 MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
+				__func__, __LINE__, ret);
+		goto out;
+	}
+
+	max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+
+	alrm->enabled = 0;
+	ret = regmap_read(info->max77802->regmap,
+			  MAX77802_RTC_AE1, &val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
+			__func__, __LINE__, ret);
+		goto out;
+	}
+	if (val)
+		alrm->enabled = 1;
+
+	alrm->pending = 0;
+	ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
+				__func__, __LINE__, ret);
+		goto out;
+	}
+
+	if (val & (1 << 2)) /* RTCA1 */
+		alrm->pending = 1;
+
+out:
+	mutex_unlock(&info->lock);
+	return 0;
+}
+
+static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
+{
+	int ret;
+
+	if (!mutex_is_locked(&info->lock))
+		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_write(info->max77802->regmap,
+			   MAX77802_RTC_AE1, 0);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+			__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+	return ret;
+}
+
+static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
+{
+	int ret;
+
+	if (!mutex_is_locked(&info->lock))
+		dev_warn(info->dev, "%s: should have mutex locked\n",
+			 __func__);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_write(info->max77802->regmap,
+				   MAX77802_RTC_AE1,
+				   ALARM_ENABLE_VALUE);
+
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+	return ret;
+}
+
+static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	ret = max77802_rtc_tm_to_data(&alrm->time, data);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_stop_alarm(info);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				 MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+	if (ret < 0)
+		goto out;
+
+	if (alrm->enabled)
+		ret = max77802_rtc_start_alarm(info);
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enabled)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&info->lock);
+	if (enabled)
+		ret = max77802_rtc_start_alarm(info);
+	else
+		ret = max77802_rtc_stop_alarm(info);
+	mutex_unlock(&info->lock);
+
+	return ret;
+}
+
+static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
+{
+	struct max77802_rtc_info *info = data;
+
+	dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
+
+	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+	return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max77802_rtc_ops = {
+	.read_time = max77802_rtc_read_time,
+	.set_time = max77802_rtc_set_time,
+	.read_alarm = max77802_rtc_read_alarm,
+	.set_alarm = max77802_rtc_set_alarm,
+	.alarm_irq_enable = max77802_rtc_alarm_irq_enable,
+};
+
+#ifdef MAX77802_RTC_WTSR_SMPL
+static void max77802_rtc_enable_wtsr(struct max77802_rtc_info *info, bool enable)
+{
+	int ret;
+	unsigned int val, mask;
+
+	if (enable)
+		val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
+	else
+		val = 0;
+
+	mask = WTSR_EN_MASK | WTSRT_MASK;
+
+	dev_info(info->dev, "%s: %s WTSR\n", __func__,
+			enable ? "enable" : "disable");
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_WTSR_SMPL_CNTL, mask, val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
+				__func__, ret);
+		return;
+	}
+
+	max77802_rtc_update(info, MAX77802_RTC_WRITE);
+}
+
+static void max77802_rtc_enable_smpl(struct max77802_rtc_info *info, bool enable)
+{
+	int ret;
+	unsigned int val, mask;
+
+	if (enable)
+		val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
+	else
+		val = 0;
+
+	mask = SMPL_EN_MASK | SMPLT_MASK;
+
+	dev_info(info->dev, "%s: %s SMPL\n", __func__,
+			enable ? "enable" : "disable");
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_WTSR_SMPL_CNTL, mask, val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
+				__func__, ret);
+		return;
+	}
+
+	max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	val = 0;
+	regmap_read(info->max77802->regmap, MAX77802_WTSR_SMPL_CNTL, &val);
+	dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val);
+}
+#endif /* MAX77802_RTC_WTSR_SMPL */
+
+static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
+{
+	u8 data[2];
+	int ret;
+
+	max77802_rtc_update(info, MAX77802_RTC_READ);
+
+	/* Set RTC control register : Binary mode, 24hour mdoe */
+	data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+	data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+
+	info->rtc_24hr_mode = 1;
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				MAX77802_RTC_CONTROLM, data, 2);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	/* Mask control register */
+	max77802_rtc_update(info, MAX77802_RTC_READ);
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_RTC_CONTROLM, 0x0, 0x3);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to mask CONTROLM reg(%d)\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	return ret;
+}
+
+static int max77802_rtc_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
+	struct max77802_rtc_info *info;
+	int ret;
+
+	dev_info(&pdev->dev, "%s\n", __func__);
+
+	info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	mutex_init(&info->lock);
+	info->dev = &pdev->dev;
+	info->max77802 = max77802;
+	info->rtc = max77802->i2c;
+
+	platform_set_drvdata(pdev, info);
+
+	ret = max77802_rtc_init_reg(info);
+
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
+		return ret;
+	}
+
+#ifdef MAX77802_RTC_WTSR_SMPL
+	max77802_rtc_enable_wtsr(info, true);
+	max77802_rtc_enable_smpl(info, true);
+#endif
+
+	device_init_wakeup(&pdev->dev, 1);
+
+	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
+						 &max77802_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(info->rtc_dev)) {
+		dev_info(&pdev->dev, "%s: fail\n", __func__);
+
+		ret = PTR_ERR(info->rtc_dev);
+		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+		if (ret == 0)
+			ret = -EINVAL;
+		return ret;
+	}
+	info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
+					 MAX77802_RTCIRQ_RTCA1);
+
+	if (info->virq <= 0) {
+		dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
+			MAX77802_RTCIRQ_RTCA1);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
+					max77802_rtc_alarm_irq, 0, "rtc-alarm1",
+					info);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+			info->virq, ret);
+
+	return ret;
+}
+
+static int max77802_rtc_remove(struct platform_device *pdev)
+{
+	struct max77802_rtc_info *info = platform_get_drvdata(pdev);
+
+	free_irq(info->virq, info);
+	rtc_device_unregister(info->rtc_dev);
+
+	return 0;
+}
+
+static void max77802_rtc_shutdown(struct platform_device *pdev)
+{
+#ifdef MAX77802_RTC_WTSR_SMPL
+	struct max77802_rtc_info *info = platform_get_drvdata(pdev);
+	int i;
+	u8 val = 0;
+
+	for (i = 0; i < 3; i++) {
+		max77802_rtc_enable_wtsr(info, false);
+		regmap_read(info->max77802->regmap,
+			    MAX77802_WTSR_SMPL_CNTL, &val);
+		dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__,
+				val);
+		if (val & WTSR_EN_MASK) {
+			dev_emerg(info->dev, "%s: fail to disable WTSR\n",
+					__func__);
+		} else {
+			dev_info(info->dev, "%s: success to disable WTSR\n",
+					__func__);
+			break;
+		}
+	}
+
+	/* Disable SMPL when power off */
+	max77802_rtc_enable_smpl(info, false);
+#endif /* MAX77802_RTC_WTSR_SMPL */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77802_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+		return enable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+
+static int max77802_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+		return disable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
+			 max77802_rtc_suspend, max77802_rtc_resume);
+
+static const struct platform_device_id rtc_id[] = {
+	{ "max77802-rtc", 0 },
+	{},
+};
+
+static struct platform_driver max77802_rtc_driver = {
+	.driver		= {
+		.name	= "max77802-rtc",
+		.owner	= THIS_MODULE,
+		.pm	= &max77802_rtc_pm_ops,
+	},
+	.probe		= max77802_rtc_probe,
+	.remove		= max77802_rtc_remove,
+	.shutdown	= max77802_rtc_shutdown,
+	.id_table	= rtc_id,
+};
+
+module_platform_driver(max77802_rtc_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
-- 
2.0.0.rc2


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

* [PATCH v4 13/14] rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

The MAX7802 PMIC has a Real-Time-Clock (RTC) with two alarms.
This patch adds support for the RTC and is based on a driver
added by Simon Glass to the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3: None

 drivers/rtc/Kconfig        |  10 +
 drivers/rtc/Makefile       |   1 +
 drivers/rtc/rtc-max77802.c | 637 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 648 insertions(+)
 create mode 100644 drivers/rtc/rtc-max77802.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0754f5c..e0b6495 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -288,6 +288,16 @@ config RTC_DRV_MAX77686
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-max77686.
 
+config RTC_DRV_MAX77802
+	tristate "Maxim MAX77802"
+	depends on MFD_MAX77802
+	help
+	  If you say yes here you will get support for the
+	  RTC of Maxim MAX77802 PMIC.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max77802.
+
 config RTC_DRV_RS5C372
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 70347d0..247de78 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_RTC_DRV_MAX8998)	+= rtc-max8998.o
 obj-$(CONFIG_RTC_DRV_MAX8997)	+= rtc-max8997.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MAX77686)	+= rtc-max77686.o
+obj-$(CONFIG_RTC_DRV_MAX77802)  += rtc-max77802.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MCP795)	+= rtc-mcp795.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c
new file mode 100644
index 0000000..7e5d031
--- /dev/null
+++ b/drivers/rtc/rtc-max77802.c
@@ -0,0 +1,637 @@
+/*
+ * RTC driver for Maxim MAX77802
+ *
+ * Copyright (C) 2013 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *
+ *  based on rtc-max8997.c
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77802-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT			0
+#define BCD_EN_MASK			(1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT			1
+#define MODEL24_MASK			(1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT			0
+#define RTC_UDR_MASK			(1 << RTC_UDR_SHIFT)
+#define RTC_RBUDR_SHIFT			4
+#define RTC_RBUDR_MASK			(1 << RTC_RBUDR_SHIFT)
+/* WTSR and SMPL Register */
+#define WTSRT_SHIFT			0
+#define SMPLT_SHIFT			2
+#define WTSR_EN_SHIFT			6
+#define SMPL_EN_SHIFT			7
+#define WTSRT_MASK			(3 << WTSRT_SHIFT)
+#define SMPLT_MASK			(3 << SMPLT_SHIFT)
+#define WTSR_EN_MASK			(1 << WTSR_EN_SHIFT)
+#define SMPL_EN_MASK			(1 << SMPL_EN_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT			6
+#define HOUR_PM_MASK			(1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT		7
+#define ALARM_ENABLE_MASK		(1 << ALARM_ENABLE_SHIFT)
+
+/* For the RTCAE1 register, we write this value to enable the alarm */
+#define ALARM_ENABLE_VALUE		0x77
+
+#define MAX77802_RTC_UPDATE_DELAY_US	200
+#undef MAX77802_RTC_WTSR_SMPL
+
+enum {
+	RTC_SEC = 0,
+	RTC_MIN,
+	RTC_HOUR,
+	RTC_WEEKDAY,
+	RTC_MONTH,
+	RTC_YEAR,
+	RTC_DATE,
+	RTC_NR_TIME
+};
+
+struct max77802_rtc_info {
+	struct device		*dev;
+	struct max77802_dev	*max77802;
+	struct i2c_client	*rtc;
+	struct rtc_device	*rtc_dev;
+	struct mutex		lock;
+
+	struct regmap		*regmap;
+
+	int virq;
+	int rtc_24hr_mode;
+};
+
+enum MAX77802_RTC_OP {
+	MAX77802_RTC_WRITE,
+	MAX77802_RTC_READ,
+};
+
+static inline int max77802_rtc_calculate_wday(u8 shifted)
+{
+	int counter = -1;
+
+	while (shifted) {
+		shifted >>= 1;
+		counter++;
+	}
+
+	return counter;
+}
+
+static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
+				   int rtc_24hr_mode)
+{
+	tm->tm_sec = data[RTC_SEC] & 0xff;
+	tm->tm_min = data[RTC_MIN] & 0xff;
+	if (rtc_24hr_mode)
+		tm->tm_hour = data[RTC_HOUR] & 0x1f;
+	else {
+		tm->tm_hour = data[RTC_HOUR] & 0x0f;
+		if (data[RTC_HOUR] & HOUR_PM_MASK)
+			tm->tm_hour += 12;
+	}
+
+	tm->tm_wday = max77802_rtc_calculate_wday(data[RTC_WEEKDAY] & 0xff);
+	tm->tm_mday = data[RTC_DATE] & 0x1f;
+	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
+
+	tm->tm_year = data[RTC_YEAR] & 0xff;
+	tm->tm_yday = 0;
+	tm->tm_isdst = 0;
+}
+
+static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+	data[RTC_SEC] = tm->tm_sec;
+	data[RTC_MIN] = tm->tm_min;
+	data[RTC_HOUR] = tm->tm_hour;
+	data[RTC_WEEKDAY] = 1 << tm->tm_wday;
+	data[RTC_DATE] = tm->tm_mday;
+	data[RTC_MONTH] = tm->tm_mon + 1;
+	data[RTC_YEAR] = tm->tm_year;
+
+	return 0;
+}
+
+static int max77802_rtc_update(struct max77802_rtc_info *info,
+	enum MAX77802_RTC_OP op)
+{
+	int ret;
+	unsigned int data;
+
+	if (op == MAX77802_RTC_WRITE)
+		data = 1 << RTC_UDR_SHIFT;
+	else
+		data = 1 << RTC_RBUDR_SHIFT;
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_RTC_UPDATE0, data, data);
+	if (ret < 0)
+		dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
+				__func__, ret, data);
+	else {
+		/* Minimum delay required before RTC update. */
+		usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
+			     MAX77802_RTC_UPDATE_DELAY_US * 2);
+	}
+
+	return ret;
+}
+
+static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_read(info->max77802->regmap,
+				MAX77802_RTC_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
+			ret);
+		goto out;
+	}
+
+	max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+
+	ret = rtc_valid_tm(tm);
+
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	ret = max77802_rtc_tm_to_data(tm, data);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&info->lock);
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				 MAX77802_RTC_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
+			ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_read(info->max77802->regmap,
+				 MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
+				__func__, __LINE__, ret);
+		goto out;
+	}
+
+	max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+
+	alrm->enabled = 0;
+	ret = regmap_read(info->max77802->regmap,
+			  MAX77802_RTC_AE1, &val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
+			__func__, __LINE__, ret);
+		goto out;
+	}
+	if (val)
+		alrm->enabled = 1;
+
+	alrm->pending = 0;
+	ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
+				__func__, __LINE__, ret);
+		goto out;
+	}
+
+	if (val & (1 << 2)) /* RTCA1 */
+		alrm->pending = 1;
+
+out:
+	mutex_unlock(&info->lock);
+	return 0;
+}
+
+static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
+{
+	int ret;
+
+	if (!mutex_is_locked(&info->lock))
+		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_write(info->max77802->regmap,
+			   MAX77802_RTC_AE1, 0);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+			__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+	return ret;
+}
+
+static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
+{
+	int ret;
+
+	if (!mutex_is_locked(&info->lock))
+		dev_warn(info->dev, "%s: should have mutex locked\n",
+			 __func__);
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_write(info->max77802->regmap,
+				   MAX77802_RTC_AE1,
+				   ALARM_ENABLE_VALUE);
+
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+	return ret;
+}
+
+static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[RTC_NR_TIME];
+	int ret;
+
+	ret = max77802_rtc_tm_to_data(&alrm->time, data);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&info->lock);
+
+	ret = max77802_rtc_stop_alarm(info);
+	if (ret < 0)
+		goto out;
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				 MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+	if (ret < 0)
+		goto out;
+
+	if (alrm->enabled)
+		ret = max77802_rtc_start_alarm(info);
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int max77802_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enabled)
+{
+	struct max77802_rtc_info *info = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&info->lock);
+	if (enabled)
+		ret = max77802_rtc_start_alarm(info);
+	else
+		ret = max77802_rtc_stop_alarm(info);
+	mutex_unlock(&info->lock);
+
+	return ret;
+}
+
+static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
+{
+	struct max77802_rtc_info *info = data;
+
+	dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
+
+	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+	return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max77802_rtc_ops = {
+	.read_time = max77802_rtc_read_time,
+	.set_time = max77802_rtc_set_time,
+	.read_alarm = max77802_rtc_read_alarm,
+	.set_alarm = max77802_rtc_set_alarm,
+	.alarm_irq_enable = max77802_rtc_alarm_irq_enable,
+};
+
+#ifdef MAX77802_RTC_WTSR_SMPL
+static void max77802_rtc_enable_wtsr(struct max77802_rtc_info *info, bool enable)
+{
+	int ret;
+	unsigned int val, mask;
+
+	if (enable)
+		val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
+	else
+		val = 0;
+
+	mask = WTSR_EN_MASK | WTSRT_MASK;
+
+	dev_info(info->dev, "%s: %s WTSR\n", __func__,
+			enable ? "enable" : "disable");
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_WTSR_SMPL_CNTL, mask, val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
+				__func__, ret);
+		return;
+	}
+
+	max77802_rtc_update(info, MAX77802_RTC_WRITE);
+}
+
+static void max77802_rtc_enable_smpl(struct max77802_rtc_info *info, bool enable)
+{
+	int ret;
+	unsigned int val, mask;
+
+	if (enable)
+		val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
+	else
+		val = 0;
+
+	mask = SMPL_EN_MASK | SMPLT_MASK;
+
+	dev_info(info->dev, "%s: %s SMPL\n", __func__,
+			enable ? "enable" : "disable");
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_WTSR_SMPL_CNTL, mask, val);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
+				__func__, ret);
+		return;
+	}
+
+	max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	val = 0;
+	regmap_read(info->max77802->regmap, MAX77802_WTSR_SMPL_CNTL, &val);
+	dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val);
+}
+#endif /* MAX77802_RTC_WTSR_SMPL */
+
+static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
+{
+	u8 data[2];
+	int ret;
+
+	max77802_rtc_update(info, MAX77802_RTC_READ);
+
+	/* Set RTC control register : Binary mode, 24hour mdoe */
+	data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+	data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+
+	info->rtc_24hr_mode = 1;
+
+	ret = regmap_bulk_write(info->max77802->regmap,
+				MAX77802_RTC_CONTROLM, data, 2);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	/* Mask control register */
+	max77802_rtc_update(info, MAX77802_RTC_READ);
+
+	ret = regmap_update_bits(info->max77802->regmap,
+				 MAX77802_RTC_CONTROLM, 0x0, 0x3);
+	if (ret < 0) {
+		dev_err(info->dev, "%s: fail to mask CONTROLM reg(%d)\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+	return ret;
+}
+
+static int max77802_rtc_probe(struct platform_device *pdev)
+{
+	struct max77802_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
+	struct max77802_rtc_info *info;
+	int ret;
+
+	dev_info(&pdev->dev, "%s\n", __func__);
+
+	info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	mutex_init(&info->lock);
+	info->dev = &pdev->dev;
+	info->max77802 = max77802;
+	info->rtc = max77802->i2c;
+
+	platform_set_drvdata(pdev, info);
+
+	ret = max77802_rtc_init_reg(info);
+
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
+		return ret;
+	}
+
+#ifdef MAX77802_RTC_WTSR_SMPL
+	max77802_rtc_enable_wtsr(info, true);
+	max77802_rtc_enable_smpl(info, true);
+#endif
+
+	device_init_wakeup(&pdev->dev, 1);
+
+	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
+						 &max77802_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(info->rtc_dev)) {
+		dev_info(&pdev->dev, "%s: fail\n", __func__);
+
+		ret = PTR_ERR(info->rtc_dev);
+		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+		if (ret == 0)
+			ret = -EINVAL;
+		return ret;
+	}
+	info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
+					 MAX77802_RTCIRQ_RTCA1);
+
+	if (info->virq <= 0) {
+		dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
+			MAX77802_RTCIRQ_RTCA1);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
+					max77802_rtc_alarm_irq, 0, "rtc-alarm1",
+					info);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+			info->virq, ret);
+
+	return ret;
+}
+
+static int max77802_rtc_remove(struct platform_device *pdev)
+{
+	struct max77802_rtc_info *info = platform_get_drvdata(pdev);
+
+	free_irq(info->virq, info);
+	rtc_device_unregister(info->rtc_dev);
+
+	return 0;
+}
+
+static void max77802_rtc_shutdown(struct platform_device *pdev)
+{
+#ifdef MAX77802_RTC_WTSR_SMPL
+	struct max77802_rtc_info *info = platform_get_drvdata(pdev);
+	int i;
+	u8 val = 0;
+
+	for (i = 0; i < 3; i++) {
+		max77802_rtc_enable_wtsr(info, false);
+		regmap_read(info->max77802->regmap,
+			    MAX77802_WTSR_SMPL_CNTL, &val);
+		dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__,
+				val);
+		if (val & WTSR_EN_MASK) {
+			dev_emerg(info->dev, "%s: fail to disable WTSR\n",
+					__func__);
+		} else {
+			dev_info(info->dev, "%s: success to disable WTSR\n",
+					__func__);
+			break;
+		}
+	}
+
+	/* Disable SMPL when power off */
+	max77802_rtc_enable_smpl(info, false);
+#endif /* MAX77802_RTC_WTSR_SMPL */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77802_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+		return enable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+
+static int max77802_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+		return disable_irq_wake(info->virq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
+			 max77802_rtc_suspend, max77802_rtc_resume);
+
+static const struct platform_device_id rtc_id[] = {
+	{ "max77802-rtc", 0 },
+	{},
+};
+
+static struct platform_driver max77802_rtc_driver = {
+	.driver		= {
+		.name	= "max77802-rtc",
+		.owner	= THIS_MODULE,
+		.pm	= &max77802_rtc_pm_ops,
+	},
+	.probe		= max77802_rtc_probe,
+	.remove		= max77802_rtc_remove,
+	.shutdown	= max77802_rtc_shutdown,
+	.id_table	= rtc_id,
+};
+
+module_platform_driver(max77802_rtc_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
-- 
2.0.0.rc2

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

* [PATCH v4 14/14] ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
  2014-06-25 19:03 ` Javier Martinez Canillas
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Lee Jones
  Cc: Samuel Ortiz, Mark Brown, Mike Turquette, Liam Girdwood,
	Alessandro Zummo, Kukjin Kim, Doug Anderson, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel,
	Javier Martinez Canillas

Peach pit and pi boards uses a Maxim 77802 power management
IC to drive regulators and its Real Time Clock. This patch
adds support for this chip.

These are the device nodes and pinctrl configuration that
are present on the Peach pit DeviceTree source file in the
the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Add support for Exynos5800 based Peach pi board. Suggested by Doug Anderson.
 - Model the actual regulators relationship instead of a simplistic model.
   Suggested by Mark Brown.

Changes since v2: None

Changes since v1:
 - Use "regulators" for child node instead of "voltage-regulators" to be
   consistent with other PMIC. Suggested by Mark Brown.
 - Use regulators node names instead of the deprecated "regulator-compatible"
   property. Suggested by Mark Brown.

 arch/arm/boot/dts/exynos5420-peach-pit.dts | 343 +++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos5800-peach-pi.dts  | 343 +++++++++++++++++++++++++++++
 2 files changed, 686 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index b2f1237..d124394 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -143,6 +143,311 @@
 	ddc = <&i2c_2>;
 };
 
+&hsi2c_4 {
+	status = "okay";
+	clock-frequency = <400000>;
+
+	max77802-pmic@9 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&gpx3>;
+		interrupts = <1 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&max77802_irq>, <&pmic_selb>,
+			    <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>;
+		wakeup-source;
+		reg = <0x9>;
+		#clock-cells = <1>;
+
+		/* Using idx 1 means warm reset will get good voltage */
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 2 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 3 GPIO_ACTIVE_HIGH>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 GPIO_ACTIVE_HIGH>,
+						<&gph0 3 GPIO_ACTIVE_HIGH>,
+						<&gph0 4 GPIO_ACTIVE_HIGH>,
+						<&gph0 5 GPIO_ACTIVE_HIGH>,
+						<&gph0 6 GPIO_ACTIVE_HIGH>;
+
+		inb1-supply = <&tps65090_dcdc2>;
+		inb2-supply = <&tps65090_dcdc1>;
+		inb3-supply = <&tps65090_dcdc2>;
+		inb4-supply = <&tps65090_dcdc2>;
+		inb5-supply = <&tps65090_dcdc1>;
+		inb6-supply = <&tps65090_dcdc2>;
+		inb7-supply = <&tps65090_dcdc1>;
+		inb8-supply = <&tps65090_dcdc1>;
+		inb9-supply = <&tps65090_dcdc1>;
+		inb10-supply = <&tps65090_dcdc1>;
+
+		inl1-supply = <&buck5_reg>;
+		inl2-supply = <&buck7_reg>;
+		inl3-supply = <&buck9_reg>;
+		inl4-supply = <&buck9_reg>;
+		inl5-supply = <&buck9_reg>;
+		inl6-supply = <&tps65090_dcdc2>;
+		inl7-supply = <&buck9_reg>;
+		inl9-supply = <&tps65090_dcdc2>;
+		inl10-supply = <&buck7_reg>;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck5_reg: BUCK5 {
+				regulator-name = "vdd_1v2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck6_reg: BUCK6 {
+				regulator-name = "vdd_kfc";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck7_reg: BUCK7 {
+				regulator-name = "vdd_1v35";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck8_reg: BUCK8 {
+				regulator-name = "vdd_emmc";
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck9_reg: BUCK9 {
+				regulator-name = "vdd_2v";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck10_reg: BUCK10 {
+				regulator-name = "vdd_1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo1_reg: LDO1 {
+				regulator-name = "vdd_1v0";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo2_reg: LDO2 {
+				regulator-name = "vdd_1v2_2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo3_reg: LDO3 {
+				regulator-name = "vdd_1v8_3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			vqmmc_sdcard: ldo4_reg: LDO4 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+
+			};
+			ldo5_reg: LDO5 {
+				regulator-name = "vdd_1v8_5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo6_reg: LDO6 {
+				regulator-name = "vdd_1v8_6";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo7_reg: LDO7 {
+				regulator-name = "vdd_1v8_7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo8_reg: LDO8 {
+				regulator-name = "vdd_ldo8";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo9_reg: LDO9 {
+				regulator-name = "vdd_ldo9";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo10_reg: LDO10 {
+				regulator-name = "vdd_ldo10";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo11_reg: LDO11 {
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo12_reg: LDO12 {
+				regulator-name = "vdd_ldo12";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+			ldo13_reg: LDO13 {
+				regulator-name = "vdd_ldo13";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo14_reg: LDO14 {
+				regulator-name = "vdd_ldo14";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo15_reg: LDO15 {
+				regulator-name = "vdd_ldo15";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo17_reg: LDO17 {
+				regulator-name = "vdd_g3ds";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+			};
+			ldo18_reg: LDO18 {
+				regulator-name = "ldo_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo19_reg: LDO19 {
+				regulator-name = "ldo_19";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo20_reg: LDO20 {
+				regulator-name = "ldo_20";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo21_reg: LDO21 {
+				regulator-name = "ldo_21";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo23_reg: LDO23 {
+				regulator-name = "ld0_23";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo24_reg: LDO24 {
+				regulator-name = "ldo_24";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo25_reg: LDO25 {
+				regulator-name = "ldo_25";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo26_reg: LDO26 {
+				regulator-name = "ldo_26";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo27_reg: LDO27 {
+				regulator-name = "ldo_27";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo28_reg: LDO28 {
+				regulator-name = "ldo_28";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo29_reg: LDO29 {
+				regulator-name = "ldo_29";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo30_reg: LDO30 {
+				regulator-name = "vdd_mifs";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo32_reg: LDO32 {
+				regulator-name = "ldo_32";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo33_reg: LDO33 {
+				regulator-name = "ldo_33";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo34_reg: LDO34 {
+				regulator-name = "ldo_34";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo35_reg: LDO35 {
+				regulator-name = "ldo_35";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				inl2-supply = <&buck7_reg>;
+			};
+		};
+	};
+};
+
 &hsi2c_7 {
 	status = "okay";
 
@@ -264,12 +569,42 @@
 		samsung,pin-drv = <0>;
 	};
 
+	max77802_irq: max77802-irq {
+		samsung,pins = "gpx3-1";
+		samsung,pin-function = <0>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
 		samsung,pin-pud = <1>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_dvs_1: pmic-dvs-1 {
+		samsung,pins = "gpy7-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_2 {
+	pmic_dvs_2: pmic-dvs-2 {
+		samsung,pins = "gpj4-2";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pmic_dvs_3: pmic-dvs-3 {
+		samsung,pins = "gpj4-3";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &pinctrl_3 {
@@ -299,6 +634,14 @@
 		samsung,pin-pud = <0>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_selb: pmic-selb {
+		samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
+			       "gph0-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &rtc {
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 5c60bbe..c36c9ce 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -141,6 +141,311 @@
 	ddc = <&i2c_2>;
 };
 
+&hsi2c_4 {
+	status = "okay";
+	clock-frequency = <400000>;
+
+	max77802-pmic@9 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&gpx3>;
+		interrupts = <1 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&max77802_irq>, <&pmic_selb>,
+			    <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>;
+		wakeup-source;
+		reg = <0x9>;
+		#clock-cells = <1>;
+
+		/* Using idx 1 means warm reset will get good voltage */
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 2 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 3 GPIO_ACTIVE_HIGH>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 GPIO_ACTIVE_HIGH>,
+						<&gph0 3 GPIO_ACTIVE_HIGH>,
+						<&gph0 4 GPIO_ACTIVE_HIGH>,
+						<&gph0 5 GPIO_ACTIVE_HIGH>,
+						<&gph0 6 GPIO_ACTIVE_HIGH>;
+
+		inb1-supply = <&tps65090_dcdc2>;
+		inb2-supply = <&tps65090_dcdc1>;
+		inb3-supply = <&tps65090_dcdc2>;
+		inb4-supply = <&tps65090_dcdc2>;
+		inb5-supply = <&tps65090_dcdc1>;
+		inb6-supply = <&tps65090_dcdc2>;
+		inb7-supply = <&tps65090_dcdc1>;
+		inb8-supply = <&tps65090_dcdc1>;
+		inb9-supply = <&tps65090_dcdc1>;
+		inb10-supply = <&tps65090_dcdc1>;
+
+		inl1-supply = <&buck5_reg>;
+		inl2-supply = <&buck7_reg>;
+		inl3-supply = <&buck9_reg>;
+		inl4-supply = <&buck9_reg>;
+		inl5-supply = <&buck9_reg>;
+		inl6-supply = <&tps65090_dcdc2>;
+		inl7-supply = <&buck9_reg>;
+		inl9-supply = <&tps65090_dcdc2>;
+		inl10-supply = <&buck7_reg>;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck5_reg: BUCK5 {
+				regulator-name = "vdd_1v2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck6_reg: BUCK6 {
+				regulator-name = "vdd_kfc";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck7_reg: BUCK7 {
+				regulator-name = "vdd_1v35";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck8_reg: BUCK8 {
+				regulator-name = "vdd_emmc";
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck9_reg: BUCK9 {
+				regulator-name = "vdd_2v";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck10_reg: BUCK10 {
+				regulator-name = "vdd_1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo1_reg: LDO1 {
+				regulator-name = "vdd_1v0";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo2_reg: LDO2 {
+				regulator-name = "vdd_1v2_2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo3_reg: LDO3 {
+				regulator-name = "vdd_1v8_3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			vqmmc_sdcard: ldo4_reg: LDO4 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+
+			};
+			ldo5_reg: LDO5 {
+				regulator-name = "vdd_1v8_5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo6_reg: LDO6 {
+				regulator-name = "vdd_1v8_6";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo7_reg: LDO7 {
+				regulator-name = "vdd_1v8_7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo8_reg: LDO8 {
+				regulator-name = "vdd_ldo8";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo9_reg: LDO9 {
+				regulator-name = "vdd_ldo9";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo10_reg: LDO10 {
+				regulator-name = "vdd_ldo10";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo11_reg: LDO11 {
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo12_reg: LDO12 {
+				regulator-name = "vdd_ldo12";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+			ldo13_reg: LDO13 {
+				regulator-name = "vdd_ldo13";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo14_reg: LDO14 {
+				regulator-name = "vdd_ldo14";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo15_reg: LDO15 {
+				regulator-name = "vdd_ldo15";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo17_reg: LDO17 {
+				regulator-name = "vdd_g3ds";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+			};
+			ldo18_reg: LDO18 {
+				regulator-name = "ldo_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo19_reg: LDO19 {
+				regulator-name = "ldo_19";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo20_reg: LDO20 {
+				regulator-name = "ldo_20";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo21_reg: LDO21 {
+				regulator-name = "ldo_21";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo23_reg: LDO23 {
+				regulator-name = "ld0_23";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo24_reg: LDO24 {
+				regulator-name = "ldo_24";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo25_reg: LDO25 {
+				regulator-name = "ldo_25";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo26_reg: LDO26 {
+				regulator-name = "ldo_26";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo27_reg: LDO27 {
+				regulator-name = "ldo_27";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo28_reg: LDO28 {
+				regulator-name = "ldo_28";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo29_reg: LDO29 {
+				regulator-name = "ldo_29";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo30_reg: LDO30 {
+				regulator-name = "vdd_mifs";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo32_reg: LDO32 {
+				regulator-name = "ldo_32";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo33_reg: LDO33 {
+				regulator-name = "ldo_33";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo34_reg: LDO34 {
+				regulator-name = "ldo_34";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo35_reg: LDO35 {
+				regulator-name = "ldo_35";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				inl2-supply = <&buck7_reg>;
+			};
+		};
+	};
+};
+
 &hsi2c_7 {
 	status = "okay";
 
@@ -262,12 +567,42 @@
 		samsung,pin-drv = <0>;
 	};
 
+	max77802_irq: max77802-irq {
+		samsung,pins = "gpx3-1";
+		samsung,pin-function = <0>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
 		samsung,pin-pud = <1>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_dvs_1: pmic-dvs-1 {
+		samsung,pins = "gpy7-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_2 {
+	pmic_dvs_2: pmic-dvs-2 {
+		samsung,pins = "gpj4-2";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pmic_dvs_3: pmic-dvs-3 {
+		samsung,pins = "gpj4-3";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &pinctrl_3 {
@@ -297,6 +632,14 @@
 		samsung,pin-pud = <0>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_selb: pmic-selb {
+		samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
+			       "gph0-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &rtc {
-- 
2.0.0.rc2


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

* [PATCH v4 14/14] ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
@ 2014-06-25 19:03   ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-25 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

Peach pit and pi boards uses a Maxim 77802 power management
IC to drive regulators and its Real Time Clock. This patch
adds support for this chip.

These are the device nodes and pinctrl configuration that
are present on the Peach pit DeviceTree source file in the
the Chrome OS kernel 3.8 tree.

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Add support for Exynos5800 based Peach pi board. Suggested by Doug Anderson.
 - Model the actual regulators relationship instead of a simplistic model.
   Suggested by Mark Brown.

Changes since v2: None

Changes since v1:
 - Use "regulators" for child node instead of "voltage-regulators" to be
   consistent with other PMIC. Suggested by Mark Brown.
 - Use regulators node names instead of the deprecated "regulator-compatible"
   property. Suggested by Mark Brown.

 arch/arm/boot/dts/exynos5420-peach-pit.dts | 343 +++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos5800-peach-pi.dts  | 343 +++++++++++++++++++++++++++++
 2 files changed, 686 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index b2f1237..d124394 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -143,6 +143,311 @@
 	ddc = <&i2c_2>;
 };
 
+&hsi2c_4 {
+	status = "okay";
+	clock-frequency = <400000>;
+
+	max77802-pmic at 9 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&gpx3>;
+		interrupts = <1 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&max77802_irq>, <&pmic_selb>,
+			    <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>;
+		wakeup-source;
+		reg = <0x9>;
+		#clock-cells = <1>;
+
+		/* Using idx 1 means warm reset will get good voltage */
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 2 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 3 GPIO_ACTIVE_HIGH>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 GPIO_ACTIVE_HIGH>,
+						<&gph0 3 GPIO_ACTIVE_HIGH>,
+						<&gph0 4 GPIO_ACTIVE_HIGH>,
+						<&gph0 5 GPIO_ACTIVE_HIGH>,
+						<&gph0 6 GPIO_ACTIVE_HIGH>;
+
+		inb1-supply = <&tps65090_dcdc2>;
+		inb2-supply = <&tps65090_dcdc1>;
+		inb3-supply = <&tps65090_dcdc2>;
+		inb4-supply = <&tps65090_dcdc2>;
+		inb5-supply = <&tps65090_dcdc1>;
+		inb6-supply = <&tps65090_dcdc2>;
+		inb7-supply = <&tps65090_dcdc1>;
+		inb8-supply = <&tps65090_dcdc1>;
+		inb9-supply = <&tps65090_dcdc1>;
+		inb10-supply = <&tps65090_dcdc1>;
+
+		inl1-supply = <&buck5_reg>;
+		inl2-supply = <&buck7_reg>;
+		inl3-supply = <&buck9_reg>;
+		inl4-supply = <&buck9_reg>;
+		inl5-supply = <&buck9_reg>;
+		inl6-supply = <&tps65090_dcdc2>;
+		inl7-supply = <&buck9_reg>;
+		inl9-supply = <&tps65090_dcdc2>;
+		inl10-supply = <&buck7_reg>;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck5_reg: BUCK5 {
+				regulator-name = "vdd_1v2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck6_reg: BUCK6 {
+				regulator-name = "vdd_kfc";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck7_reg: BUCK7 {
+				regulator-name = "vdd_1v35";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck8_reg: BUCK8 {
+				regulator-name = "vdd_emmc";
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck9_reg: BUCK9 {
+				regulator-name = "vdd_2v";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck10_reg: BUCK10 {
+				regulator-name = "vdd_1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo1_reg: LDO1 {
+				regulator-name = "vdd_1v0";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo2_reg: LDO2 {
+				regulator-name = "vdd_1v2_2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo3_reg: LDO3 {
+				regulator-name = "vdd_1v8_3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			vqmmc_sdcard: ldo4_reg: LDO4 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+
+			};
+			ldo5_reg: LDO5 {
+				regulator-name = "vdd_1v8_5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo6_reg: LDO6 {
+				regulator-name = "vdd_1v8_6";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo7_reg: LDO7 {
+				regulator-name = "vdd_1v8_7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo8_reg: LDO8 {
+				regulator-name = "vdd_ldo8";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo9_reg: LDO9 {
+				regulator-name = "vdd_ldo9";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo10_reg: LDO10 {
+				regulator-name = "vdd_ldo10";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo11_reg: LDO11 {
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo12_reg: LDO12 {
+				regulator-name = "vdd_ldo12";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+			ldo13_reg: LDO13 {
+				regulator-name = "vdd_ldo13";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo14_reg: LDO14 {
+				regulator-name = "vdd_ldo14";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo15_reg: LDO15 {
+				regulator-name = "vdd_ldo15";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo17_reg: LDO17 {
+				regulator-name = "vdd_g3ds";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+			};
+			ldo18_reg: LDO18 {
+				regulator-name = "ldo_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo19_reg: LDO19 {
+				regulator-name = "ldo_19";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo20_reg: LDO20 {
+				regulator-name = "ldo_20";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo21_reg: LDO21 {
+				regulator-name = "ldo_21";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo23_reg: LDO23 {
+				regulator-name = "ld0_23";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo24_reg: LDO24 {
+				regulator-name = "ldo_24";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo25_reg: LDO25 {
+				regulator-name = "ldo_25";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo26_reg: LDO26 {
+				regulator-name = "ldo_26";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo27_reg: LDO27 {
+				regulator-name = "ldo_27";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo28_reg: LDO28 {
+				regulator-name = "ldo_28";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo29_reg: LDO29 {
+				regulator-name = "ldo_29";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo30_reg: LDO30 {
+				regulator-name = "vdd_mifs";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo32_reg: LDO32 {
+				regulator-name = "ldo_32";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo33_reg: LDO33 {
+				regulator-name = "ldo_33";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo34_reg: LDO34 {
+				regulator-name = "ldo_34";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo35_reg: LDO35 {
+				regulator-name = "ldo_35";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				inl2-supply = <&buck7_reg>;
+			};
+		};
+	};
+};
+
 &hsi2c_7 {
 	status = "okay";
 
@@ -264,12 +569,42 @@
 		samsung,pin-drv = <0>;
 	};
 
+	max77802_irq: max77802-irq {
+		samsung,pins = "gpx3-1";
+		samsung,pin-function = <0>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
 		samsung,pin-pud = <1>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_dvs_1: pmic-dvs-1 {
+		samsung,pins = "gpy7-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_2 {
+	pmic_dvs_2: pmic-dvs-2 {
+		samsung,pins = "gpj4-2";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pmic_dvs_3: pmic-dvs-3 {
+		samsung,pins = "gpj4-3";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &pinctrl_3 {
@@ -299,6 +634,14 @@
 		samsung,pin-pud = <0>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_selb: pmic-selb {
+		samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
+			       "gph0-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &rtc {
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 5c60bbe..c36c9ce 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -141,6 +141,311 @@
 	ddc = <&i2c_2>;
 };
 
+&hsi2c_4 {
+	status = "okay";
+	clock-frequency = <400000>;
+
+	max77802-pmic at 9 {
+		compatible = "maxim,max77802";
+		interrupt-parent = <&gpx3>;
+		interrupts = <1 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&max77802_irq>, <&pmic_selb>,
+			    <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>;
+		wakeup-source;
+		reg = <0x9>;
+		#clock-cells = <1>;
+
+		/* Using idx 1 means warm reset will get good voltage */
+		max77802,pmic-buck-default-dvs-idx = <1>;
+		max77802,pmic-buck-dvs-gpios = <&gpy7 6 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 2 GPIO_ACTIVE_HIGH>,
+					       <&gpj4 3 GPIO_ACTIVE_HIGH>;
+		max77802,pmic-buck-selb-gpios = <&gph0 2 GPIO_ACTIVE_HIGH>,
+						<&gph0 3 GPIO_ACTIVE_HIGH>,
+						<&gph0 4 GPIO_ACTIVE_HIGH>,
+						<&gph0 5 GPIO_ACTIVE_HIGH>,
+						<&gph0 6 GPIO_ACTIVE_HIGH>;
+
+		inb1-supply = <&tps65090_dcdc2>;
+		inb2-supply = <&tps65090_dcdc1>;
+		inb3-supply = <&tps65090_dcdc2>;
+		inb4-supply = <&tps65090_dcdc2>;
+		inb5-supply = <&tps65090_dcdc1>;
+		inb6-supply = <&tps65090_dcdc2>;
+		inb7-supply = <&tps65090_dcdc1>;
+		inb8-supply = <&tps65090_dcdc1>;
+		inb9-supply = <&tps65090_dcdc1>;
+		inb10-supply = <&tps65090_dcdc1>;
+
+		inl1-supply = <&buck5_reg>;
+		inl2-supply = <&buck7_reg>;
+		inl3-supply = <&buck9_reg>;
+		inl4-supply = <&buck9_reg>;
+		inl5-supply = <&buck9_reg>;
+		inl6-supply = <&tps65090_dcdc2>;
+		inl7-supply = <&buck9_reg>;
+		inl9-supply = <&tps65090_dcdc2>;
+		inl10-supply = <&buck7_reg>;
+
+		regulators {
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int_real";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck5_reg: BUCK5 {
+				regulator-name = "vdd_1v2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck6_reg: BUCK6 {
+				regulator-name = "vdd_kfc";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-ramp-delay = <12500>;
+			};
+			buck7_reg: BUCK7 {
+				regulator-name = "vdd_1v35";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck8_reg: BUCK8 {
+				regulator-name = "vdd_emmc";
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck9_reg: BUCK9 {
+				regulator-name = "vdd_2v";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			buck10_reg: BUCK10 {
+				regulator-name = "vdd_1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo1_reg: LDO1 {
+				regulator-name = "vdd_1v0";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo2_reg: LDO2 {
+				regulator-name = "vdd_1v2_2";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo3_reg: LDO3 {
+				regulator-name = "vdd_1v8_3";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			vqmmc_sdcard: ldo4_reg: LDO4 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+
+			};
+			ldo5_reg: LDO5 {
+				regulator-name = "vdd_1v8_5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo6_reg: LDO6 {
+				regulator-name = "vdd_1v8_6";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo7_reg: LDO7 {
+				regulator-name = "vdd_1v8_7";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo8_reg: LDO8 {
+				regulator-name = "vdd_ldo8";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo9_reg: LDO9 {
+				regulator-name = "vdd_ldo9";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo10_reg: LDO10 {
+				regulator-name = "vdd_ldo10";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo11_reg: LDO11 {
+				regulator-name = "vdd_ldo11";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo12_reg: LDO12 {
+				regulator-name = "vdd_ldo12";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+			ldo13_reg: LDO13 {
+				regulator-name = "vdd_ldo13";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo14_reg: LDO14 {
+				regulator-name = "vdd_ldo14";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo15_reg: LDO15 {
+				regulator-name = "vdd_ldo15";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo17_reg: LDO17 {
+				regulator-name = "vdd_g3ds";
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-always-on;
+			};
+			ldo18_reg: LDO18 {
+				regulator-name = "ldo_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo19_reg: LDO19 {
+				regulator-name = "ldo_19";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo20_reg: LDO20 {
+				regulator-name = "ldo_20";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+			ldo21_reg: LDO21 {
+				regulator-name = "ldo_21";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo23_reg: LDO23 {
+				regulator-name = "ld0_23";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo24_reg: LDO24 {
+				regulator-name = "ldo_24";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo25_reg: LDO25 {
+				regulator-name = "ldo_25";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+			ldo26_reg: LDO26 {
+				regulator-name = "ldo_26";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo27_reg: LDO27 {
+				regulator-name = "ldo_27";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+			ldo28_reg: LDO28 {
+				regulator-name = "ldo_28";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo29_reg: LDO29 {
+				regulator-name = "ldo_29";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+			ldo30_reg: LDO30 {
+				regulator-name = "vdd_mifs";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+			ldo32_reg: LDO32 {
+				regulator-name = "ldo_32";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo33_reg: LDO33 {
+				regulator-name = "ldo_33";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+			ldo34_reg: LDO34 {
+				regulator-name = "ldo_34";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+			ldo35_reg: LDO35 {
+				regulator-name = "ldo_35";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				inl2-supply = <&buck7_reg>;
+			};
+		};
+	};
+};
+
 &hsi2c_7 {
 	status = "okay";
 
@@ -262,12 +567,42 @@
 		samsung,pin-drv = <0>;
 	};
 
+	max77802_irq: max77802-irq {
+		samsung,pins = "gpx3-1";
+		samsung,pin-function = <0>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
 		samsung,pin-pud = <1>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_dvs_1: pmic-dvs-1 {
+		samsung,pins = "gpy7-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_2 {
+	pmic_dvs_2: pmic-dvs-2 {
+		samsung,pins = "gpj4-2";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pmic_dvs_3: pmic-dvs-3 {
+		samsung,pins = "gpj4-3";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &pinctrl_3 {
@@ -297,6 +632,14 @@
 		samsung,pin-pud = <0>;
 		samsung,pin-drv = <0>;
 	};
+
+	pmic_selb: pmic-selb {
+		samsung,pins = "gph0-2", "gph0-3", "gph0-4", "gph0-5",
+			       "gph0-6";
+		samsung,pin-function = <1>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
 };
 
 &rtc {
-- 
2.0.0.rc2

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

* Re: [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding
  2014-06-25 19:03   ` Javier Martinez Canillas
  (?)
@ 2014-06-25 19:54     ` Doug Anderson
  -1 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-25 19:54 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Wed, Jun 25, 2014 at 12:03 PM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Like most clock drivers, the Maxim 77686 PMIC clock binding
> follows the convention that the "#clock-cells" property is
> used to specify the number of cells in a clock provider.
>
> But the binding document is not clear enough that it shall
> be set to 1 since the PMIC support multiple clocks outputs.
>
> Also, explain that the clocks identifiers are defined in a
> header file that can be included by Device Tree source with
> client nodes to avoid using magic numbers.
>
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>
> Changes since v3:
>  - Don't change clock-names property to make clear that it's
>    the consumer clock name and should not match the producer clock.
>    Suggested by Doug Anderson.
>
>  Documentation/devicetree/bindings/clock/maxim,max77686.txt | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)

Reviewed-by: Doug Anderson <dianders@chromium.org>

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

* Re: [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding
@ 2014-06-25 19:54     ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-25 19:54 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Olof Johansson,
	Sjoerd Simons, Daniel Stone, Tomeu Vizoso, Krzysztof Kozlowski,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Wed, Jun 25, 2014 at 12:03 PM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Like most clock drivers, the Maxim 77686 PMIC clock binding
> follows the convention that the "#clock-cells" property is
> used to specify the number of cells in a clock provider.
>
> But the binding document is not clear enough that it shall
> be set to 1 since the PMIC support multiple clocks outputs.
>
> Also, explain that the clocks identifiers are defined in a
> header file that can be included by Device Tree source with
> client nodes to avoid using magic numbers.
>
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>
> Changes since v3:
>  - Don't change clock-names property to make clear that it's
>    the consumer clock name and should not match the producer clock.
>    Suggested by Doug Anderson.
>
>  Documentation/devicetree/bindings/clock/maxim,max77686.txt | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)

Reviewed-by: Doug Anderson <dianders@chromium.org>

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

* [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding
@ 2014-06-25 19:54     ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-25 19:54 UTC (permalink / raw)
  To: linux-arm-kernel

Javier,

On Wed, Jun 25, 2014 at 12:03 PM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Like most clock drivers, the Maxim 77686 PMIC clock binding
> follows the convention that the "#clock-cells" property is
> used to specify the number of cells in a clock provider.
>
> But the binding document is not clear enough that it shall
> be set to 1 since the PMIC support multiple clocks outputs.
>
> Also, explain that the clocks identifiers are defined in a
> header file that can be included by Device Tree source with
> client nodes to avoid using magic numbers.
>
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>
> Changes since v3:
>  - Don't change clock-names property to make clear that it's
>    the consumer clock name and should not match the producer clock.
>    Suggested by Doug Anderson.
>
>  Documentation/devicetree/bindings/clock/maxim,max77686.txt | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)

Reviewed-by: Doug Anderson <dianders@chromium.org>

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

* Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
  2014-06-25 19:03   ` Javier Martinez Canillas
@ 2014-06-26  9:00     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:00 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> Maxim Integrated Power Management ICs are very similar with
> regard to their clock outputs. Most of the clock drivers for
> these chips are duplicating code and are simpler enough that
> can be converted to use a generic driver to consolidate code
> and avoid duplication.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Add current copyright information. Suggested by Krzysztof Kozlowski
>  - Do a single allocation for struct max_gen_clk. Suggested by Krzysztof Kozlowski 
> 
>  drivers/clk/Kconfig       |   3 +
>  drivers/clk/Makefile      |   1 +
>  drivers/clk/clk-max-gen.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/clk-max-gen.h |  32 ++++++++
>  4 files changed, 231 insertions(+)
>  create mode 100644 drivers/clk/clk-max-gen.c
>  create mode 100644 drivers/clk/clk-max-gen.h

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof



> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 9f9c5ae..73f78e8 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -32,6 +32,9 @@ config COMMON_CLK_WM831X
>  
>  source "drivers/clk/versatile/Kconfig"
>  
> +config COMMON_CLK_MAX_GEN
> +        bool
> +
>  config COMMON_CLK_MAX77686
>  	tristate "Clock driver for Maxim 77686 MFD"
>  	depends on MFD_MAX77686
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 567f102..6c1aff6 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_BCM2835)		+= clk-bcm2835.o
>  obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
>  obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>  obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
> +obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
>  obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
>  obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
>  obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
> diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
> new file mode 100644
> index 0000000..3e9fa7e
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.c
> @@ -0,0 +1,195 @@
> +/*
> + * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * Copyright (C) 2012 Samsung Electornics
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on clk-max77686.c
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk-provider.h>
> +#include <linux/mutex.h>
> +#include <linux/clkdev.h>
> +
> +struct max_gen_clk {
> +	struct regmap *regmap;
> +	u32 mask;
> +	u32 reg;
> +	struct clk_hw hw;
> +	struct clk_lookup *lookup;
> +};
> +
> +static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
> +{
> +	return container_of(hw, struct max_gen_clk, hw);
> +}
> +
> +static int max_gen_clk_prepare(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +	return regmap_update_bits(max_gen->regmap, max_gen->reg,
> +				  max_gen->mask, max_gen->mask);
> +}
> +
> +static void max_gen_clk_unprepare(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +	regmap_update_bits(max_gen->regmap, max_gen->reg,
> +			   max_gen->mask, ~max_gen->mask);
> +}
> +
> +static int max_gen_clk_is_prepared(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +	int ret;
> +	u32 val;
> +
> +	ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
> +
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	return val & max_gen->mask;
> +}
> +
> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
> +{
> +	return 32768;
> +}
> +
> +struct clk_ops max_gen_clk_ops = {
> +	.prepare	= max_gen_clk_prepare,
> +	.unprepare	= max_gen_clk_unprepare,
> +	.is_prepared	= max_gen_clk_is_prepared,
> +	.recalc_rate	= max_gen_recalc_rate,
> +};
> +EXPORT_SYMBOL_GPL(max_gen_clk_ops);
> +
> +static struct clk *max_gen_clk_register(struct device *dev,
> +					struct max_gen_clk *max_gen)
> +{
> +	struct clk *clk;
> +	struct clk_hw *hw = &max_gen->hw;
> +
> +	clk = clk_register(dev, hw);
> +	if (IS_ERR(clk))
> +		return clk;
> +
> +	max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
> +	if (!max_gen->lookup)
> +		return ERR_PTR(-ENOMEM);
> +
> +	max_gen->lookup->con_id = hw->init->name;
> +	max_gen->lookup->clk = clk;
> +
> +	clkdev_add(max_gen->lookup);
> +
> +	return clk;
> +}
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +		      u32 reg, struct clk_init_data *clks_init, int num_init)
> +{
> +	int i, ret;
> +	struct max_gen_clk *max_gen_clks;
> +	struct clk **clocks;
> +	struct device *dev = &pdev->dev;
> +
> +	clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
> +	if (!clocks)
> +		return -ENOMEM;
> +
> +	max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
> +				    * num_init, GFP_KERNEL);
> +	if (!max_gen_clks)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < num_init; i++) {
> +		max_gen_clks[i].regmap = regmap;
> +		max_gen_clks[i].mask = 1 << i;
> +		max_gen_clks[i].reg = reg;
> +		max_gen_clks[i].hw.init = &clks_init[i];
> +
> +		clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
> +		if (IS_ERR(clocks[i])) {
> +			ret = PTR_ERR(clocks[i]);
> +			dev_err(dev, "failed to register %s\n",
> +				max_gen_clks[i].hw.init->name);
> +			goto err_clocks;
> +		}
> +	}
> +
> +	platform_set_drvdata(pdev, clocks);
> +
> +	if (dev->of_node) {
> +		struct clk_onecell_data *of_data;
> +
> +		of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
> +		if (!of_data) {
> +			ret = -ENOMEM;
> +			goto err_clocks;
> +		}
> +
> +		of_data->clks = clocks;
> +		of_data->clk_num = num_init;
> +		ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> +					  of_data);
> +
> +		if (ret) {
> +			dev_err(dev, "failed to register OF clock provider\n");
> +			goto err_clocks;
> +		}
> +	}
> +
> +	return 0;
> +
> +err_clocks:
> +	for (--i; i >= 0; --i) {
> +		clkdev_drop(max_gen_clks[i].lookup);
> +		clk_unregister(max_gen_clks[i].hw.clk);
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_probe);
> +
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init)
> +{
> +	struct clk **clocks = platform_get_drvdata(pdev);
> +	struct device *dev = pdev->dev.parent;
> +	int i;
> +
> +	if (dev->of_node)
> +		of_clk_del_provider(dev->of_node);
> +
> +	for (i = 0; i < num_init; i++) {
> +		struct clk_hw *hw = __clk_get_hw(clocks[i]);
> +		struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +		clkdev_drop(max_gen->lookup);
> +		clk_unregister(clocks[i]);
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_remove);
> diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
> new file mode 100644
> index 0000000..997e86f
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.h
> @@ -0,0 +1,32 @@
> +/*
> + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __CLK_MAX_GEN_H__
> +#define __CLK_MAX_GEN_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/clkdev.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +		      u32 reg, struct clk_init_data *clks_init, int num_init);
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init);
> +extern struct clk_ops max_gen_clk_ops;
> +
> +#endif /* __CLK_MAX_GEN_H__ */


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

* [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-26  9:00     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> Maxim Integrated Power Management ICs are very similar with
> regard to their clock outputs. Most of the clock drivers for
> these chips are duplicating code and are simpler enough that
> can be converted to use a generic driver to consolidate code
> and avoid duplication.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Add current copyright information. Suggested by Krzysztof Kozlowski
>  - Do a single allocation for struct max_gen_clk. Suggested by Krzysztof Kozlowski 
> 
>  drivers/clk/Kconfig       |   3 +
>  drivers/clk/Makefile      |   1 +
>  drivers/clk/clk-max-gen.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/clk-max-gen.h |  32 ++++++++
>  4 files changed, 231 insertions(+)
>  create mode 100644 drivers/clk/clk-max-gen.c
>  create mode 100644 drivers/clk/clk-max-gen.h

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof



> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 9f9c5ae..73f78e8 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -32,6 +32,9 @@ config COMMON_CLK_WM831X
>  
>  source "drivers/clk/versatile/Kconfig"
>  
> +config COMMON_CLK_MAX_GEN
> +        bool
> +
>  config COMMON_CLK_MAX77686
>  	tristate "Clock driver for Maxim 77686 MFD"
>  	depends on MFD_MAX77686
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 567f102..6c1aff6 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_BCM2835)		+= clk-bcm2835.o
>  obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
>  obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>  obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
> +obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
>  obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
>  obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
>  obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
> diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
> new file mode 100644
> index 0000000..3e9fa7e
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.c
> @@ -0,0 +1,195 @@
> +/*
> + * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * Copyright (C) 2012 Samsung Electornics
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on clk-max77686.c
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk-provider.h>
> +#include <linux/mutex.h>
> +#include <linux/clkdev.h>
> +
> +struct max_gen_clk {
> +	struct regmap *regmap;
> +	u32 mask;
> +	u32 reg;
> +	struct clk_hw hw;
> +	struct clk_lookup *lookup;
> +};
> +
> +static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
> +{
> +	return container_of(hw, struct max_gen_clk, hw);
> +}
> +
> +static int max_gen_clk_prepare(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +	return regmap_update_bits(max_gen->regmap, max_gen->reg,
> +				  max_gen->mask, max_gen->mask);
> +}
> +
> +static void max_gen_clk_unprepare(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +	regmap_update_bits(max_gen->regmap, max_gen->reg,
> +			   max_gen->mask, ~max_gen->mask);
> +}
> +
> +static int max_gen_clk_is_prepared(struct clk_hw *hw)
> +{
> +	struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +	int ret;
> +	u32 val;
> +
> +	ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
> +
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	return val & max_gen->mask;
> +}
> +
> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
> +{
> +	return 32768;
> +}
> +
> +struct clk_ops max_gen_clk_ops = {
> +	.prepare	= max_gen_clk_prepare,
> +	.unprepare	= max_gen_clk_unprepare,
> +	.is_prepared	= max_gen_clk_is_prepared,
> +	.recalc_rate	= max_gen_recalc_rate,
> +};
> +EXPORT_SYMBOL_GPL(max_gen_clk_ops);
> +
> +static struct clk *max_gen_clk_register(struct device *dev,
> +					struct max_gen_clk *max_gen)
> +{
> +	struct clk *clk;
> +	struct clk_hw *hw = &max_gen->hw;
> +
> +	clk = clk_register(dev, hw);
> +	if (IS_ERR(clk))
> +		return clk;
> +
> +	max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
> +	if (!max_gen->lookup)
> +		return ERR_PTR(-ENOMEM);
> +
> +	max_gen->lookup->con_id = hw->init->name;
> +	max_gen->lookup->clk = clk;
> +
> +	clkdev_add(max_gen->lookup);
> +
> +	return clk;
> +}
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +		      u32 reg, struct clk_init_data *clks_init, int num_init)
> +{
> +	int i, ret;
> +	struct max_gen_clk *max_gen_clks;
> +	struct clk **clocks;
> +	struct device *dev = &pdev->dev;
> +
> +	clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
> +	if (!clocks)
> +		return -ENOMEM;
> +
> +	max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
> +				    * num_init, GFP_KERNEL);
> +	if (!max_gen_clks)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < num_init; i++) {
> +		max_gen_clks[i].regmap = regmap;
> +		max_gen_clks[i].mask = 1 << i;
> +		max_gen_clks[i].reg = reg;
> +		max_gen_clks[i].hw.init = &clks_init[i];
> +
> +		clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
> +		if (IS_ERR(clocks[i])) {
> +			ret = PTR_ERR(clocks[i]);
> +			dev_err(dev, "failed to register %s\n",
> +				max_gen_clks[i].hw.init->name);
> +			goto err_clocks;
> +		}
> +	}
> +
> +	platform_set_drvdata(pdev, clocks);
> +
> +	if (dev->of_node) {
> +		struct clk_onecell_data *of_data;
> +
> +		of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
> +		if (!of_data) {
> +			ret = -ENOMEM;
> +			goto err_clocks;
> +		}
> +
> +		of_data->clks = clocks;
> +		of_data->clk_num = num_init;
> +		ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> +					  of_data);
> +
> +		if (ret) {
> +			dev_err(dev, "failed to register OF clock provider\n");
> +			goto err_clocks;
> +		}
> +	}
> +
> +	return 0;
> +
> +err_clocks:
> +	for (--i; i >= 0; --i) {
> +		clkdev_drop(max_gen_clks[i].lookup);
> +		clk_unregister(max_gen_clks[i].hw.clk);
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_probe);
> +
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init)
> +{
> +	struct clk **clocks = platform_get_drvdata(pdev);
> +	struct device *dev = pdev->dev.parent;
> +	int i;
> +
> +	if (dev->of_node)
> +		of_clk_del_provider(dev->of_node);
> +
> +	for (i = 0; i < num_init; i++) {
> +		struct clk_hw *hw = __clk_get_hw(clocks[i]);
> +		struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +		clkdev_drop(max_gen->lookup);
> +		clk_unregister(clocks[i]);
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_remove);
> diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
> new file mode 100644
> index 0000000..997e86f
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.h
> @@ -0,0 +1,32 @@
> +/*
> + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __CLK_MAX_GEN_H__
> +#define __CLK_MAX_GEN_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/clkdev.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +		      u32 reg, struct clk_init_data *clks_init, int num_init);
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init);
> +extern struct clk_ops max_gen_clk_ops;
> +
> +#endif /* __CLK_MAX_GEN_H__ */

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

* Re: [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system
  2014-06-25 19:03   ` Javier Martinez Canillas
@ 2014-06-26  9:03     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:03 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> From: Doug Anderson <dianders@chromium.org>
> 
> The max77686 includes an RTC that keeps power during suspend.  It's
> convenient to be able to use it as a wakeup source.
> 
> NOTE: due to wakeup ordering problems this patch alone doesn't work so
> well on exynos5250-snow.  You also need something that brings the i2c
> bus up before the max77686 wakeup runs.
> 
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Keep the note that this patch needs another change due wakeup
>    ordering problems.
> 
>  drivers/rtc/rtc-max77686.c | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof


> diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
> index d20a7f0..c1c6055 100644
> --- a/drivers/rtc/rtc-max77686.c
> +++ b/drivers/rtc/rtc-max77686.c
> @@ -583,6 +583,33 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
>  #endif /* MAX77686_RTC_WTSR_SMPL */
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int max77686_rtc_suspend(struct device *dev)
> +{
> +	if (device_may_wakeup(dev)) {
> +		struct max77686_rtc_info *info = dev_get_drvdata(dev);
> +
> +		return enable_irq_wake(info->virq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77686_rtc_resume(struct device *dev)
> +{
> +	if (device_may_wakeup(dev)) {
> +		struct max77686_rtc_info *info = dev_get_drvdata(dev);
> +
> +		return disable_irq_wake(info->virq);
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
> +			 max77686_rtc_suspend, max77686_rtc_resume);
> +
>  static const struct platform_device_id rtc_id[] = {
>  	{ "max77686-rtc", 0 },
>  	{},
> @@ -592,6 +619,7 @@ static struct platform_driver max77686_rtc_driver = {
>  	.driver		= {
>  		.name	= "max77686-rtc",
>  		.owner	= THIS_MODULE,
> +		.pm	= &max77686_rtc_pm_ops,
>  	},
>  	.probe		= max77686_rtc_probe,
>  	.shutdown	= max77686_rtc_shutdown,


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

* [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system
@ 2014-06-26  9:03     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:03 UTC (permalink / raw)
  To: linux-arm-kernel

On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> From: Doug Anderson <dianders@chromium.org>
> 
> The max77686 includes an RTC that keeps power during suspend.  It's
> convenient to be able to use it as a wakeup source.
> 
> NOTE: due to wakeup ordering problems this patch alone doesn't work so
> well on exynos5250-snow.  You also need something that brings the i2c
> bus up before the max77686 wakeup runs.
> 
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Keep the note that this patch needs another change due wakeup
>    ordering problems.
> 
>  drivers/rtc/rtc-max77686.c | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof


> diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
> index d20a7f0..c1c6055 100644
> --- a/drivers/rtc/rtc-max77686.c
> +++ b/drivers/rtc/rtc-max77686.c
> @@ -583,6 +583,33 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
>  #endif /* MAX77686_RTC_WTSR_SMPL */
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int max77686_rtc_suspend(struct device *dev)
> +{
> +	if (device_may_wakeup(dev)) {
> +		struct max77686_rtc_info *info = dev_get_drvdata(dev);
> +
> +		return enable_irq_wake(info->virq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77686_rtc_resume(struct device *dev)
> +{
> +	if (device_may_wakeup(dev)) {
> +		struct max77686_rtc_info *info = dev_get_drvdata(dev);
> +
> +		return disable_irq_wake(info->virq);
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
> +			 max77686_rtc_suspend, max77686_rtc_resume);
> +
>  static const struct platform_device_id rtc_id[] = {
>  	{ "max77686-rtc", 0 },
>  	{},
> @@ -592,6 +619,7 @@ static struct platform_driver max77686_rtc_driver = {
>  	.driver		= {
>  		.name	= "max77686-rtc",
>  		.owner	= THIS_MODULE,
> +		.pm	= &max77686_rtc_pm_ops,
>  	},
>  	.probe		= max77686_rtc_probe,
>  	.shutdown	= max77686_rtc_shutdown,

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-25 19:03   ` Javier Martinez Canillas
@ 2014-06-26  9:31     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:31 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hi,

Just a few nit-picks below but overall everything looks fine:

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>


On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> Maxim MAX77802 is a power management chip that contains 10 high
> efficiency Buck regulators, 32 Low-dropout (LDO) regulators used
> to power up application processors and peripherals, a 2-channel
> 32kHz clock outputs, a Real-Time-Clock (RTC) and a I2C interface
> to program the individual regulators, clocks outputs and the RTC.
> 
> This patch adds the core support for MAX77802 PMIC and is based
> on a driver added by Simon Glass to the Chrome OS kernel 3.8 tree.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>

(...)

> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f001487..e795bfe 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
>  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
>  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
>  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> +obj-$(CONFIG_MFD_MAX77802)      += max77802.o
>  obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
>  max8925-objs			:= max8925-core.o max8925-i2c.o
>  obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
> diff --git a/drivers/mfd/max77802.c b/drivers/mfd/max77802.c
> new file mode 100644
> index 0000000..3d477fb
> --- /dev/null
> +++ b/drivers/mfd/max77802.c
> @@ -0,0 +1,366 @@
> +/*
> + * max77802.c - mfd core driver for the Maxim 77802
> + *
> + * Copyright (C) 2013-2014 Google, Inc
> + * Simon Glass <sjg@chromium.org>
> + *
> + * Copyright (C) 2012 Samsung Electronics
> + * Chiwoong Byun <woong.byun@smasung.com>
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on max8997.c
> + */
> +
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/mfd/max77802.h>
> +#include <linux/mfd/max77802-private.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/err.h>
> +
> +static const struct mfd_cell max77802_devs[] = {
> +	{ .name = "max77802-pmic", },
> +	{ .name = "max77802-clk", },
> +	{ .name = "max77802-rtc", },
> +};
> +
> +static bool max77802_pmic_is_accessible_reg(struct device *dev,
> +					    unsigned int reg)
> +{
> +	return (reg >= MAX77802_REG_DEVICE_ID && reg < MAX77802_REG_PMIC_END);
> +}
> +
> +static bool max77802_rtc_is_accessible_reg(struct device *dev,
> +					   unsigned int reg)
> +{
> +	return (reg >= MAX77802_RTC_INT && reg < MAX77802_RTC_END);
> +}
> +
> +static bool max77802_is_accessible_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_accessible_reg(dev, reg) ||
> +		max77802_rtc_is_accessible_reg(dev, reg));
> +}
> +
> +static bool max77802_pmic_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (reg == MAX77802_REG_INTSRC || reg == MAX77802_REG_INT1 ||
> +		reg == MAX77802_REG_INT2);
> +}
> +
> +static bool max77802_rtc_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (reg == MAX77802_RTC_INT ||
> +		reg == MAX77802_RTC_UPDATE0 ||
> +		reg == MAX77802_RTC_UPDATE1);
> +}
> +
> +static bool max77802_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_precious_reg(dev, reg) ||
> +		max77802_rtc_is_precious_reg(dev, reg));
> +}
> +
> +static bool max77802_pmic_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_is_precious_reg(dev, reg) ||
> +		reg == MAX77802_REG_STATUS1 || reg == MAX77802_REG_STATUS2 ||
> +		reg == MAX77802_REG_PWRON);
> +}
> +
> +static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_rtc_is_precious_reg(dev, reg) ||
> +		reg == MAX77802_RTC_SEC ||
> +		reg == MAX77802_RTC_MIN ||
> +		reg == MAX77802_RTC_HOUR ||
> +		reg == MAX77802_RTC_WEEKDAY ||
> +		reg == MAX77802_RTC_MONTH ||
> +		reg == MAX77802_RTC_YEAR ||
> +		reg == MAX77802_RTC_DATE);
> +}
> +
> +static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_volatile_reg(dev, reg) ||
> +		max77802_rtc_is_volatile_reg(dev, reg));
> +}
> +
> +static struct regmap_config max77802_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = max77802_is_accessible_reg,
> +	.readable_reg = max77802_is_accessible_reg,
> +	.precious_reg = max77802_is_precious_reg,
> +	.volatile_reg = max77802_is_volatile_reg,
> +	.name = "max77802-pmic",
> +	.cache_type = REGCACHE_RBTREE,
> +};
> +
> +static const struct regmap_irq max77802_irqs[] = {
> +	/* INT1 interrupts */
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ONKEY1S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_MRSTB_MSK, },
> +	/* INT2 interrupts */
> +	{ .reg_offset = 1, .mask = MAX77802_INT2_140C_MSK, },
> +	{ .reg_offset = 1, .mask = MAX77802_INT2_120C_MSK, },
> +};
> +
> +static const struct regmap_irq_chip max77802_irq_chip = {
> +	.name			= "max77802-pmic",
> +	.status_base		= MAX77802_REG_INT1,
> +	.mask_base		= MAX77802_REG_INT1MSK,
> +	.num_regs		= 2,
> +	.irqs			= max77802_irqs,
> +	.num_irqs		= ARRAY_SIZE(max77802_irqs),
> +};
> +
> +static const struct regmap_irq max77802_rtc_irqs[] = {
> +	/* RTC interrupts */
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC60S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA1_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA2_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_SMPL_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC1S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_WTSR_MSK, },
> +};
> +
> +static const struct regmap_irq_chip max77802_rtc_irq_chip = {
> +	.name			= "max77802-rtc",
> +	.status_base		= MAX77802_RTC_INT,
> +	.mask_base		= MAX77802_RTC_INTM,
> +	.num_regs		= 1,
> +	.irqs			= max77802_rtc_irqs,
> +	.num_irqs		= ARRAY_SIZE(max77802_rtc_irqs),
> +};
> +
> +#ifdef CONFIG_OF
> +static struct of_device_id max77802_pmic_dt_match[] = {
> +	{.compatible = "maxim,max77802", .data = NULL},
> +	{},
> +};
> +
> +static void max77802_dt_parse_dvs_gpio(struct device *dev,
> +				       struct max77802_platform_data *pd,
> +				       struct device_node *np)
> +{
> +	int i;
> +
> +	/*
> +	 * NOTE: we don't consider GPIO errors fatal; board may have some lines
> +	 * directly pulled high or low and thus doesn't specify them.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++)
> +		pd->buck_gpio_dvs[i] =
> +			devm_gpiod_get_index(dev, "max77802,pmic-buck-dvs", i);
> +
> +	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++)
> +		pd->buck_gpio_selb[i] =
> +			devm_gpiod_get_index(dev, "max77802,pmic-buck-selb", i);
> +}
> +
> +static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
> +								  *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct max77802_platform_data *pd;
> +
> +	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return NULL;
> +
> +	/* Read default index and ignore errors, since default is 0 */
> +	of_property_read_u32(np, "max77802,pmic-buck-default-dvs-idx",
> +			     &pd->buck_default_idx);
> +
> +	max77802_dt_parse_dvs_gpio(dev, pd, np);
> +
> +	dev->platform_data = pd;
> +	return pd;
> +}
> +#else
> +static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
> +								  *dev)
> +{
> +	return 0;
> +}
> +#endif
> +
> +static int max77802_i2c_probe(struct i2c_client *i2c,
> +			      const struct i2c_device_id *id)
> +{
> +	struct max77802_dev *max77802 = NULL;
> +	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
> +	unsigned int data;
> +	int ret = 0;
> +
> +	if (i2c->dev.of_node)
> +		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
> +
> +	if (!pdata) {
> +		dev_err(&i2c->dev, "No platform data found.\n");
> +		return -EIO;
> +	}
> +
> +	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
> +				GFP_KERNEL);
> +	if (max77802 == NULL)

It is inconsistent. Before you used "(!pd)" and "(!pdata)" so maybe
stick to one format?

> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c, max77802);
> +
> +	max77802->dev = &i2c->dev;
> +	max77802->i2c = i2c;
> +	max77802->type = id->driver_data;
> +
> +	max77802->wakeup = pdata->wakeup;
> +	max77802->irq = i2c->irq;
> +
> +	max77802->regmap = devm_regmap_init_i2c(i2c, &max77802_regmap_config);
> +	if (IS_ERR(max77802->regmap)) {
> +		ret = PTR_ERR(max77802->regmap);
> +		dev_err(max77802->dev, "Failed to allocate register map: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	if (regmap_read(max77802->regmap,
> +			 MAX77802_REG_DEVICE_ID, &data) < 0) {
> +		dev_err(max77802->dev,
> +			"device not found on this channel\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
> +				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
> +				  IRQF_SHARED, 0, &max77802_irq_chip,
> +				  &max77802->irq_data);
> +	if (ret != 0) {
> +		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
> +		return ret;
> +	}
> +	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
> +				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
> +				  IRQF_SHARED, 0, &max77802_rtc_irq_chip,
> +				  &max77802->rtc_irq_data);
> +	if (ret != 0) {
> +		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
> +		goto err_del_irqc;
> +	}
> +
> +	ret = mfd_add_devices(max77802->dev, -1, max77802_devs,
> +			      ARRAY_SIZE(max77802_devs), NULL, 0, NULL);
> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
> +		goto err_del_rtc_irqc;
> +	}
> +
> +	return 0;
> +
> +err_del_rtc_irqc:
> +	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
> +err_del_irqc:
> +	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
> +	return ret;
> +}
> +
> +static int max77802_i2c_remove(struct i2c_client *i2c)
> +{
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	mfd_remove_devices(max77802->dev);
> +
> +	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
> +	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id max77802_i2c_id[] = {
> +	{ "max77802", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, max77802_i2c_id);
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int max77802_suspend(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		enable_irq_wake(max77802->irq);
> +
> +	disable_irq(max77802->irq);

Can you add short comment why this is needed? I know why but just for
future generations which will wonder: "why do we need to disable the IRQ
while suspending?" :). Especially that this is rather a workaround for
issue in other driver (I2C bus).

> +
> +	return 0;
> +}
> +
> +static int max77802_resume(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		disable_irq_wake(max77802->irq);
> +
> +	enable_irq(max77802->irq);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static SIMPLE_DEV_PM_OPS(max77802_pm, max77802_suspend, max77802_resume);
> +
> +static struct i2c_driver max77802_i2c_driver = {
> +	.driver = {
> +		   .name = "max77802",
> +		   .owner = THIS_MODULE,
> +		   .pm = &max77802_pm,
> +		   .of_match_table = of_match_ptr(max77802_pmic_dt_match),
> +	},
> +	.probe = max77802_i2c_probe,
> +	.remove = max77802_i2c_remove,
> +	.id_table = max77802_i2c_id,
> +};
> +
> +static int __init max77802_i2c_init(void)
> +{
> +	return i2c_add_driver(&max77802_i2c_driver);
> +}
> +/* init early so consumer devices can complete system boot */
> +subsys_initcall(max77802_i2c_init);
> +
> +static void __exit max77802_i2c_exit(void)
> +{
> +	i2c_del_driver(&max77802_i2c_driver);
> +}
> +module_exit(max77802_i2c_exit);
> +
> +MODULE_DESCRIPTION("MAXIM 77802 multi-function core driver");
> +MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77802-private.h b/include/linux/mfd/max77802-private.h
> new file mode 100644
> index 0000000..7539ab4
> --- /dev/null
> +++ b/include/linux/mfd/max77802-private.h
> @@ -0,0 +1,307 @@
> +/*
> + * max77802-private.h - Voltage regulator driver for the Maxim 77802
> + *
> + *  Copyright (C) 2012 Samsung Electrnoics
> + *  Chiwoong Byun <woong.byun@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_MFD_MAX77802_PRIV_H
> +#define __LINUX_MFD_MAX77802_PRIV_H
> +
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/module.h>
> +
> +#define MAX77802_REG_INVALID		(0xff)
> +
> +enum max77802_pmic_reg {
> +	MAX77802_REG_DEVICE_ID		= 0x00,
> +	MAX77802_REG_INTSRC		= 0x01,
> +	MAX77802_REG_INT1		= 0x02,
> +	MAX77802_REG_INT2		= 0x03,
> +
> +	MAX77802_REG_INT1MSK		= 0x04,
> +	MAX77802_REG_INT2MSK		= 0x05,
> +
> +	MAX77802_REG_STATUS1		= 0x06,
> +	MAX77802_REG_STATUS2		= 0x07,
> +
> +	MAX77802_REG_PWRON		= 0x08,
> +	/* Reserved: 0x09 */
> +	MAX77802_REG_MRSTB		= 0x0A,
> +	MAX77802_REG_EPWRHOLD		= 0x0B,
> +	/* Reserved: 0x0C-0x0D */
> +	MAX77802_REG_BOOSTCTRL		= 0x0E,
> +	MAX77802_REG_BOOSTOUT		= 0x0F,
> +
> +	MAX77802_REG_BUCK1CTRL		= 0x10,
> +	MAX77802_REG_BUCK1DVS1		= 0x11,
> +	MAX77802_REG_BUCK1DVS2		= 0x12,
> +	MAX77802_REG_BUCK1DVS3		= 0x13,
> +	MAX77802_REG_BUCK1DVS4		= 0x14,
> +	MAX77802_REG_BUCK1DVS5		= 0x15,
> +	MAX77802_REG_BUCK1DVS6		= 0x16,
> +	MAX77802_REG_BUCK1DVS7		= 0x17,
> +	MAX77802_REG_BUCK1DVS8		= 0x18,
> +	/* Reserved: 0x19 */
> +	MAX77802_REG_BUCK2CTRL1		= 0x1A,
> +	MAX77802_REG_BUCK2CTRL2		= 0x1B,
> +	MAX77802_REG_BUCK2PHTRAN	= 0x1C,
> +	MAX77802_REG_BUCK2DVS1		= 0x1D,
> +	MAX77802_REG_BUCK2DVS2		= 0x1E,
> +	MAX77802_REG_BUCK2DVS3		= 0x1F,
> +	MAX77802_REG_BUCK2DVS4		= 0x20,
> +	MAX77802_REG_BUCK2DVS5		= 0x21,
> +	MAX77802_REG_BUCK2DVS6		= 0x22,
> +	MAX77802_REG_BUCK2DVS7		= 0x23,
> +	MAX77802_REG_BUCK2DVS8		= 0x24,
> +	/* Reserved: 0x25-0x26 */
> +	MAX77802_REG_BUCK3CTRL1		= 0x27,
> +	MAX77802_REG_BUCK3DVS1		= 0x28,
> +	MAX77802_REG_BUCK3DVS2		= 0x29,
> +	MAX77802_REG_BUCK3DVS3		= 0x2A,
> +	MAX77802_REG_BUCK3DVS4		= 0x2B,
> +	MAX77802_REG_BUCK3DVS5		= 0x2C,
> +	MAX77802_REG_BUCK3DVS6		= 0x2D,
> +	MAX77802_REG_BUCK3DVS7		= 0x2E,
> +	MAX77802_REG_BUCK3DVS8		= 0x2F,
> +	/* Reserved: 0x30-0x36 */
> +	MAX77802_REG_BUCK4CTRL1		= 0x37,
> +	MAX77802_REG_BUCK4DVS1		= 0x38,
> +	MAX77802_REG_BUCK4DVS2		= 0x39,
> +	MAX77802_REG_BUCK4DVS3		= 0x3A,
> +	MAX77802_REG_BUCK4DVS4		= 0x3B,
> +	MAX77802_REG_BUCK4DVS5		= 0x3C,
> +	MAX77802_REG_BUCK4DVS6		= 0x3D,
> +	MAX77802_REG_BUCK4DVS7		= 0x3E,
> +	MAX77802_REG_BUCK4DVS8		= 0x3F,
> +	/* Reserved: 0x40 */
> +	MAX77802_REG_BUCK5CTRL		= 0x41,
> +	MAX77802_REG_BUCK5OUT		= 0x42,
> +	/* Reserved: 0x43 */
> +	MAX77802_REG_BUCK6CTRL		= 0x44,
> +	MAX77802_REG_BUCK6DVS1		= 0x45,
> +	MAX77802_REG_BUCK6DVS2		= 0x46,
> +	MAX77802_REG_BUCK6DVS3		= 0x47,
> +	MAX77802_REG_BUCK6DVS4		= 0x48,
> +	MAX77802_REG_BUCK6DVS5		= 0x49,
> +	MAX77802_REG_BUCK6DVS6		= 0x4A,
> +	MAX77802_REG_BUCK6DVS7		= 0x4B,
> +	MAX77802_REG_BUCK6DVS8		= 0x4C,
> +	/* Reserved: 0x4D */
> +	MAX77802_REG_BUCK7CTRL		= 0x4E,
> +	MAX77802_REG_BUCK7OUT		= 0x4F,
> +	/* Reserved: 0x50 */
> +	MAX77802_REG_BUCK8CTRL		= 0x51,
> +	MAX77802_REG_BUCK8OUT		= 0x52,
> +	/* Reserved: 0x53 */
> +	MAX77802_REG_BUCK9CTRL		= 0x54,
> +	MAX77802_REG_BUCK9OUT		= 0x55,
> +	/* Reserved: 0x56 */
> +	MAX77802_REG_BUCK10CTRL		= 0x57,
> +	MAX77802_REG_BUCK10OUT		= 0x58,
> +
> +	/* Reserved: 0x59-0x5F */
> +
> +	MAX77802_REG_LDO1CTRL1		= 0x60,
> +	MAX77802_REG_LDO2CTRL1		= 0x61,
> +	MAX77802_REG_LDO3CTRL1		= 0x62,
> +	MAX77802_REG_LDO4CTRL1		= 0x63,
> +	MAX77802_REG_LDO5CTRL1		= 0x64,
> +	MAX77802_REG_LDO6CTRL1		= 0x65,
> +	MAX77802_REG_LDO7CTRL1		= 0x66,
> +	MAX77802_REG_LDO8CTRL1		= 0x67,
> +	MAX77802_REG_LDO9CTRL1		= 0x68,
> +	MAX77802_REG_LDO10CTRL1		= 0x69,
> +	MAX77802_REG_LDO11CTRL1		= 0x6A,
> +	MAX77802_REG_LDO12CTRL1		= 0x6B,
> +	MAX77802_REG_LDO13CTRL1		= 0x6C,
> +	MAX77802_REG_LDO14CTRL1		= 0x6D,
> +	MAX77802_REG_LDO15CTRL1		= 0x6E,
> +	/* Reserved: 0x6F */
> +	MAX77802_REG_LDO17CTRL1		= 0x70,
> +	MAX77802_REG_LDO18CTRL1		= 0x71,
> +	MAX77802_REG_LDO19CTRL1		= 0x72,
> +	MAX77802_REG_LDO20CTRL1		= 0x73,
> +	MAX77802_REG_LDO21CTRL1		= 0x74,
> +	MAX77802_REG_LDO22CTRL1		= 0x75,
> +	MAX77802_REG_LDO23CTRL1		= 0x76,
> +	MAX77802_REG_LDO24CTRL1		= 0x77,
> +	MAX77802_REG_LDO25CTRL1		= 0x78,
> +	MAX77802_REG_LDO26CTRL1		= 0x79,
> +	MAX77802_REG_LDO27CTRL1		= 0x7A,
> +	MAX77802_REG_LDO28CTRL1		= 0x7B,
> +	MAX77802_REG_LDO29CTRL1		= 0x7C,
> +	MAX77802_REG_LDO30CTRL1		= 0x7D,
> +	/* Reserved: 0x7E */
> +	MAX77802_REG_LDO32CTRL1		= 0x7F,
> +	MAX77802_REG_LDO33CTRL1		= 0x80,
> +	MAX77802_REG_LDO34CTRL1		= 0x81,
> +	MAX77802_REG_LDO35CTRL1		= 0x82,
> +	/* Reserved: 0x83-0x8F */
> +	MAX77802_REG_LDO1CTRL2		= 0x90,
> +	MAX77802_REG_LDO2CTRL2		= 0x91,
> +	MAX77802_REG_LDO3CTRL2		= 0x92,
> +	MAX77802_REG_LDO4CTRL2		= 0x93,
> +	MAX77802_REG_LDO5CTRL2		= 0x94,
> +	MAX77802_REG_LDO6CTRL2		= 0x95,
> +	MAX77802_REG_LDO7CTRL2		= 0x96,
> +	MAX77802_REG_LDO8CTRL2		= 0x97,
> +	MAX77802_REG_LDO9CTRL2		= 0x98,
> +	MAX77802_REG_LDO10CTRL2		= 0x99,
> +	MAX77802_REG_LDO11CTRL2		= 0x9A,
> +	MAX77802_REG_LDO12CTRL2		= 0x9B,
> +	MAX77802_REG_LDO13CTRL2		= 0x9C,
> +	MAX77802_REG_LDO14CTRL2		= 0x9D,
> +	MAX77802_REG_LDO15CTRL2		= 0x9E,
> +	/* Reserved: 0x9F */
> +	MAX77802_REG_LDO17CTRL2		= 0xA0,
> +	MAX77802_REG_LDO18CTRL2		= 0xA1,
> +	MAX77802_REG_LDO19CTRL2		= 0xA2,
> +	MAX77802_REG_LDO20CTRL2		= 0xA3,
> +	MAX77802_REG_LDO21CTRL2		= 0xA4,
> +	MAX77802_REG_LDO22CTRL2		= 0xA5,
> +	MAX77802_REG_LDO23CTRL2		= 0xA6,
> +	MAX77802_REG_LDO24CTRL2		= 0xA7,
> +	MAX77802_REG_LDO25CTRL2		= 0xA8,
> +	MAX77802_REG_LDO26CTRL2		= 0xA9,
> +	MAX77802_REG_LDO27CTRL2		= 0xAA,
> +	MAX77802_REG_LDO28CTRL2		= 0xAB,
> +	MAX77802_REG_LDO29CTRL2		= 0xAC,
> +	MAX77802_REG_LDO30CTRL2		= 0xAD,
> +	/* Reserved: 0xAE */
> +	MAX77802_REG_LDO32CTRL2		= 0xAF,
> +	MAX77802_REG_LDO33CTRL2		= 0xB0,
> +	MAX77802_REG_LDO34CTRL2		= 0xB1,
> +	MAX77802_REG_LDO35CTRL2		= 0xB2,
> +	/* Reserved: 0xB3 */
> +
> +	MAX77802_REG_BBAT_CHG		= 0xB4,
> +	MAX77802_REG_32KHZ		= 0xB5,
> +
> +	MAX77802_REG_PMIC_END		= 0xB6,
> +};
> +
> +enum max77802_rtc_reg {
> +	MAX77802_RTC_INT		= 0xC0,
> +	MAX77802_RTC_INTM		= 0xC1,
> +	MAX77802_RTC_CONTROLM		= 0xC2,
> +	MAX77802_RTC_CONTROL		= 0xC3,
> +	MAX77802_RTC_UPDATE0		= 0xC4,
> +	MAX77802_RTC_UPDATE1		= 0xC5,
> +	MAX77802_WTSR_SMPL_CNTL		= 0xC6,
> +	MAX77802_RTC_SEC		= 0xC7,
> +	MAX77802_RTC_MIN		= 0xC8,
> +	MAX77802_RTC_HOUR		= 0xC9,
> +	MAX77802_RTC_WEEKDAY		= 0xCA,
> +	MAX77802_RTC_MONTH		= 0xCB,
> +	MAX77802_RTC_YEAR		= 0xCC,
> +	MAX77802_RTC_DATE		= 0xCD,
> +	MAX77802_RTC_AE1		= 0xCE,
> +	MAX77802_ALARM1_SEC		= 0xCF,
> +	MAX77802_ALARM1_MIN		= 0xD0,
> +	MAX77802_ALARM1_HOUR		= 0xD1,
> +	MAX77802_ALARM1_WEEKDAY		= 0xD2,
> +	MAX77802_ALARM1_MONTH		= 0xD3,
> +	MAX77802_ALARM1_YEAR		= 0xD4,
> +	MAX77802_ALARM1_DATE		= 0xD5,
> +	MAX77802_RTC_AE2		= 0xD6,
> +	MAX77802_ALARM2_SEC		= 0xD7,
> +	MAX77802_ALARM2_MIN		= 0xD8,
> +	MAX77802_ALARM2_HOUR		= 0xD9,
> +	MAX77802_ALARM2_WEEKDAY		= 0xDA,
> +	MAX77802_ALARM2_MONTH		= 0xDB,
> +	MAX77802_ALARM2_YEAR		= 0xDC,
> +	MAX77802_ALARM2_DATE		= 0xDD,
> +
> +	MAX77802_RTC_END		= 0xDF,
> +};
> +
> +#define MAX77802_IRQSRC_PMIC            (0)

Shouldn't it be BIT(0) or BIT(1)? It looks odd.

> +#define MAX77802_IRQSRC_RTC	        BIT(0)

Anyway, are these defines used anywhere? Seems not. 

Best regards,
Krzysztof


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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26  9:31     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26  9:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Just a few nit-picks below but overall everything looks fine:

Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>


On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> Maxim MAX77802 is a power management chip that contains 10 high
> efficiency Buck regulators, 32 Low-dropout (LDO) regulators used
> to power up application processors and peripherals, a 2-channel
> 32kHz clock outputs, a Real-Time-Clock (RTC) and a I2C interface
> to program the individual regulators, clocks outputs and the RTC.
> 
> This patch adds the core support for MAX77802 PMIC and is based
> on a driver added by Simon Glass to the Chrome OS kernel 3.8 tree.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>

(...)

> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f001487..e795bfe 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
>  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
>  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
>  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> +obj-$(CONFIG_MFD_MAX77802)      += max77802.o
>  obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
>  max8925-objs			:= max8925-core.o max8925-i2c.o
>  obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
> diff --git a/drivers/mfd/max77802.c b/drivers/mfd/max77802.c
> new file mode 100644
> index 0000000..3d477fb
> --- /dev/null
> +++ b/drivers/mfd/max77802.c
> @@ -0,0 +1,366 @@
> +/*
> + * max77802.c - mfd core driver for the Maxim 77802
> + *
> + * Copyright (C) 2013-2014 Google, Inc
> + * Simon Glass <sjg@chromium.org>
> + *
> + * Copyright (C) 2012 Samsung Electronics
> + * Chiwoong Byun <woong.byun@smasung.com>
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on max8997.c
> + */
> +
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/mfd/max77802.h>
> +#include <linux/mfd/max77802-private.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/err.h>
> +
> +static const struct mfd_cell max77802_devs[] = {
> +	{ .name = "max77802-pmic", },
> +	{ .name = "max77802-clk", },
> +	{ .name = "max77802-rtc", },
> +};
> +
> +static bool max77802_pmic_is_accessible_reg(struct device *dev,
> +					    unsigned int reg)
> +{
> +	return (reg >= MAX77802_REG_DEVICE_ID && reg < MAX77802_REG_PMIC_END);
> +}
> +
> +static bool max77802_rtc_is_accessible_reg(struct device *dev,
> +					   unsigned int reg)
> +{
> +	return (reg >= MAX77802_RTC_INT && reg < MAX77802_RTC_END);
> +}
> +
> +static bool max77802_is_accessible_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_accessible_reg(dev, reg) ||
> +		max77802_rtc_is_accessible_reg(dev, reg));
> +}
> +
> +static bool max77802_pmic_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (reg == MAX77802_REG_INTSRC || reg == MAX77802_REG_INT1 ||
> +		reg == MAX77802_REG_INT2);
> +}
> +
> +static bool max77802_rtc_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (reg == MAX77802_RTC_INT ||
> +		reg == MAX77802_RTC_UPDATE0 ||
> +		reg == MAX77802_RTC_UPDATE1);
> +}
> +
> +static bool max77802_is_precious_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_precious_reg(dev, reg) ||
> +		max77802_rtc_is_precious_reg(dev, reg));
> +}
> +
> +static bool max77802_pmic_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_is_precious_reg(dev, reg) ||
> +		reg == MAX77802_REG_STATUS1 || reg == MAX77802_REG_STATUS2 ||
> +		reg == MAX77802_REG_PWRON);
> +}
> +
> +static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_rtc_is_precious_reg(dev, reg) ||
> +		reg == MAX77802_RTC_SEC ||
> +		reg == MAX77802_RTC_MIN ||
> +		reg == MAX77802_RTC_HOUR ||
> +		reg == MAX77802_RTC_WEEKDAY ||
> +		reg == MAX77802_RTC_MONTH ||
> +		reg == MAX77802_RTC_YEAR ||
> +		reg == MAX77802_RTC_DATE);
> +}
> +
> +static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	return (max77802_pmic_is_volatile_reg(dev, reg) ||
> +		max77802_rtc_is_volatile_reg(dev, reg));
> +}
> +
> +static struct regmap_config max77802_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = max77802_is_accessible_reg,
> +	.readable_reg = max77802_is_accessible_reg,
> +	.precious_reg = max77802_is_precious_reg,
> +	.volatile_reg = max77802_is_volatile_reg,
> +	.name = "max77802-pmic",
> +	.cache_type = REGCACHE_RBTREE,
> +};
> +
> +static const struct regmap_irq max77802_irqs[] = {
> +	/* INT1 interrupts */
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_PWRONR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_JIGONBR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBF_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ACOKBR_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_ONKEY1S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_INT1_MRSTB_MSK, },
> +	/* INT2 interrupts */
> +	{ .reg_offset = 1, .mask = MAX77802_INT2_140C_MSK, },
> +	{ .reg_offset = 1, .mask = MAX77802_INT2_120C_MSK, },
> +};
> +
> +static const struct regmap_irq_chip max77802_irq_chip = {
> +	.name			= "max77802-pmic",
> +	.status_base		= MAX77802_REG_INT1,
> +	.mask_base		= MAX77802_REG_INT1MSK,
> +	.num_regs		= 2,
> +	.irqs			= max77802_irqs,
> +	.num_irqs		= ARRAY_SIZE(max77802_irqs),
> +};
> +
> +static const struct regmap_irq max77802_rtc_irqs[] = {
> +	/* RTC interrupts */
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC60S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA1_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTCA2_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_SMPL_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_RTC1S_MSK, },
> +	{ .reg_offset = 0, .mask = MAX77802_RTCINT_WTSR_MSK, },
> +};
> +
> +static const struct regmap_irq_chip max77802_rtc_irq_chip = {
> +	.name			= "max77802-rtc",
> +	.status_base		= MAX77802_RTC_INT,
> +	.mask_base		= MAX77802_RTC_INTM,
> +	.num_regs		= 1,
> +	.irqs			= max77802_rtc_irqs,
> +	.num_irqs		= ARRAY_SIZE(max77802_rtc_irqs),
> +};
> +
> +#ifdef CONFIG_OF
> +static struct of_device_id max77802_pmic_dt_match[] = {
> +	{.compatible = "maxim,max77802", .data = NULL},
> +	{},
> +};
> +
> +static void max77802_dt_parse_dvs_gpio(struct device *dev,
> +				       struct max77802_platform_data *pd,
> +				       struct device_node *np)
> +{
> +	int i;
> +
> +	/*
> +	 * NOTE: we don't consider GPIO errors fatal; board may have some lines
> +	 * directly pulled high or low and thus doesn't specify them.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++)
> +		pd->buck_gpio_dvs[i] =
> +			devm_gpiod_get_index(dev, "max77802,pmic-buck-dvs", i);
> +
> +	for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++)
> +		pd->buck_gpio_selb[i] =
> +			devm_gpiod_get_index(dev, "max77802,pmic-buck-selb", i);
> +}
> +
> +static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
> +								  *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct max77802_platform_data *pd;
> +
> +	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return NULL;
> +
> +	/* Read default index and ignore errors, since default is 0 */
> +	of_property_read_u32(np, "max77802,pmic-buck-default-dvs-idx",
> +			     &pd->buck_default_idx);
> +
> +	max77802_dt_parse_dvs_gpio(dev, pd, np);
> +
> +	dev->platform_data = pd;
> +	return pd;
> +}
> +#else
> +static struct max77802_platform_data *max77802_i2c_parse_dt_pdata(struct device
> +								  *dev)
> +{
> +	return 0;
> +}
> +#endif
> +
> +static int max77802_i2c_probe(struct i2c_client *i2c,
> +			      const struct i2c_device_id *id)
> +{
> +	struct max77802_dev *max77802 = NULL;
> +	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
> +	unsigned int data;
> +	int ret = 0;
> +
> +	if (i2c->dev.of_node)
> +		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
> +
> +	if (!pdata) {
> +		dev_err(&i2c->dev, "No platform data found.\n");
> +		return -EIO;
> +	}
> +
> +	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
> +				GFP_KERNEL);
> +	if (max77802 == NULL)

It is inconsistent. Before you used "(!pd)" and "(!pdata)" so maybe
stick to one format?

> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c, max77802);
> +
> +	max77802->dev = &i2c->dev;
> +	max77802->i2c = i2c;
> +	max77802->type = id->driver_data;
> +
> +	max77802->wakeup = pdata->wakeup;
> +	max77802->irq = i2c->irq;
> +
> +	max77802->regmap = devm_regmap_init_i2c(i2c, &max77802_regmap_config);
> +	if (IS_ERR(max77802->regmap)) {
> +		ret = PTR_ERR(max77802->regmap);
> +		dev_err(max77802->dev, "Failed to allocate register map: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	if (regmap_read(max77802->regmap,
> +			 MAX77802_REG_DEVICE_ID, &data) < 0) {
> +		dev_err(max77802->dev,
> +			"device not found on this channel\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
> +				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
> +				  IRQF_SHARED, 0, &max77802_irq_chip,
> +				  &max77802->irq_data);
> +	if (ret != 0) {
> +		dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
> +		return ret;
> +	}
> +	ret = regmap_add_irq_chip(max77802->regmap, max77802->irq,
> +				  IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
> +				  IRQF_SHARED, 0, &max77802_rtc_irq_chip,
> +				  &max77802->rtc_irq_data);
> +	if (ret != 0) {
> +		dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
> +		goto err_del_irqc;
> +	}
> +
> +	ret = mfd_add_devices(max77802->dev, -1, max77802_devs,
> +			      ARRAY_SIZE(max77802_devs), NULL, 0, NULL);
> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
> +		goto err_del_rtc_irqc;
> +	}
> +
> +	return 0;
> +
> +err_del_rtc_irqc:
> +	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
> +err_del_irqc:
> +	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
> +	return ret;
> +}
> +
> +static int max77802_i2c_remove(struct i2c_client *i2c)
> +{
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	mfd_remove_devices(max77802->dev);
> +
> +	regmap_del_irq_chip(max77802->irq, max77802->rtc_irq_data);
> +	regmap_del_irq_chip(max77802->irq, max77802->irq_data);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id max77802_i2c_id[] = {
> +	{ "max77802", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, max77802_i2c_id);
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int max77802_suspend(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		enable_irq_wake(max77802->irq);
> +
> +	disable_irq(max77802->irq);

Can you add short comment why this is needed? I know why but just for
future generations which will wonder: "why do we need to disable the IRQ
while suspending?" :). Especially that this is rather a workaround for
issue in other driver (I2C bus).

> +
> +	return 0;
> +}
> +
> +static int max77802_resume(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		disable_irq_wake(max77802->irq);
> +
> +	enable_irq(max77802->irq);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static SIMPLE_DEV_PM_OPS(max77802_pm, max77802_suspend, max77802_resume);
> +
> +static struct i2c_driver max77802_i2c_driver = {
> +	.driver = {
> +		   .name = "max77802",
> +		   .owner = THIS_MODULE,
> +		   .pm = &max77802_pm,
> +		   .of_match_table = of_match_ptr(max77802_pmic_dt_match),
> +	},
> +	.probe = max77802_i2c_probe,
> +	.remove = max77802_i2c_remove,
> +	.id_table = max77802_i2c_id,
> +};
> +
> +static int __init max77802_i2c_init(void)
> +{
> +	return i2c_add_driver(&max77802_i2c_driver);
> +}
> +/* init early so consumer devices can complete system boot */
> +subsys_initcall(max77802_i2c_init);
> +
> +static void __exit max77802_i2c_exit(void)
> +{
> +	i2c_del_driver(&max77802_i2c_driver);
> +}
> +module_exit(max77802_i2c_exit);
> +
> +MODULE_DESCRIPTION("MAXIM 77802 multi-function core driver");
> +MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77802-private.h b/include/linux/mfd/max77802-private.h
> new file mode 100644
> index 0000000..7539ab4
> --- /dev/null
> +++ b/include/linux/mfd/max77802-private.h
> @@ -0,0 +1,307 @@
> +/*
> + * max77802-private.h - Voltage regulator driver for the Maxim 77802
> + *
> + *  Copyright (C) 2012 Samsung Electrnoics
> + *  Chiwoong Byun <woong.byun@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __LINUX_MFD_MAX77802_PRIV_H
> +#define __LINUX_MFD_MAX77802_PRIV_H
> +
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/module.h>
> +
> +#define MAX77802_REG_INVALID		(0xff)
> +
> +enum max77802_pmic_reg {
> +	MAX77802_REG_DEVICE_ID		= 0x00,
> +	MAX77802_REG_INTSRC		= 0x01,
> +	MAX77802_REG_INT1		= 0x02,
> +	MAX77802_REG_INT2		= 0x03,
> +
> +	MAX77802_REG_INT1MSK		= 0x04,
> +	MAX77802_REG_INT2MSK		= 0x05,
> +
> +	MAX77802_REG_STATUS1		= 0x06,
> +	MAX77802_REG_STATUS2		= 0x07,
> +
> +	MAX77802_REG_PWRON		= 0x08,
> +	/* Reserved: 0x09 */
> +	MAX77802_REG_MRSTB		= 0x0A,
> +	MAX77802_REG_EPWRHOLD		= 0x0B,
> +	/* Reserved: 0x0C-0x0D */
> +	MAX77802_REG_BOOSTCTRL		= 0x0E,
> +	MAX77802_REG_BOOSTOUT		= 0x0F,
> +
> +	MAX77802_REG_BUCK1CTRL		= 0x10,
> +	MAX77802_REG_BUCK1DVS1		= 0x11,
> +	MAX77802_REG_BUCK1DVS2		= 0x12,
> +	MAX77802_REG_BUCK1DVS3		= 0x13,
> +	MAX77802_REG_BUCK1DVS4		= 0x14,
> +	MAX77802_REG_BUCK1DVS5		= 0x15,
> +	MAX77802_REG_BUCK1DVS6		= 0x16,
> +	MAX77802_REG_BUCK1DVS7		= 0x17,
> +	MAX77802_REG_BUCK1DVS8		= 0x18,
> +	/* Reserved: 0x19 */
> +	MAX77802_REG_BUCK2CTRL1		= 0x1A,
> +	MAX77802_REG_BUCK2CTRL2		= 0x1B,
> +	MAX77802_REG_BUCK2PHTRAN	= 0x1C,
> +	MAX77802_REG_BUCK2DVS1		= 0x1D,
> +	MAX77802_REG_BUCK2DVS2		= 0x1E,
> +	MAX77802_REG_BUCK2DVS3		= 0x1F,
> +	MAX77802_REG_BUCK2DVS4		= 0x20,
> +	MAX77802_REG_BUCK2DVS5		= 0x21,
> +	MAX77802_REG_BUCK2DVS6		= 0x22,
> +	MAX77802_REG_BUCK2DVS7		= 0x23,
> +	MAX77802_REG_BUCK2DVS8		= 0x24,
> +	/* Reserved: 0x25-0x26 */
> +	MAX77802_REG_BUCK3CTRL1		= 0x27,
> +	MAX77802_REG_BUCK3DVS1		= 0x28,
> +	MAX77802_REG_BUCK3DVS2		= 0x29,
> +	MAX77802_REG_BUCK3DVS3		= 0x2A,
> +	MAX77802_REG_BUCK3DVS4		= 0x2B,
> +	MAX77802_REG_BUCK3DVS5		= 0x2C,
> +	MAX77802_REG_BUCK3DVS6		= 0x2D,
> +	MAX77802_REG_BUCK3DVS7		= 0x2E,
> +	MAX77802_REG_BUCK3DVS8		= 0x2F,
> +	/* Reserved: 0x30-0x36 */
> +	MAX77802_REG_BUCK4CTRL1		= 0x37,
> +	MAX77802_REG_BUCK4DVS1		= 0x38,
> +	MAX77802_REG_BUCK4DVS2		= 0x39,
> +	MAX77802_REG_BUCK4DVS3		= 0x3A,
> +	MAX77802_REG_BUCK4DVS4		= 0x3B,
> +	MAX77802_REG_BUCK4DVS5		= 0x3C,
> +	MAX77802_REG_BUCK4DVS6		= 0x3D,
> +	MAX77802_REG_BUCK4DVS7		= 0x3E,
> +	MAX77802_REG_BUCK4DVS8		= 0x3F,
> +	/* Reserved: 0x40 */
> +	MAX77802_REG_BUCK5CTRL		= 0x41,
> +	MAX77802_REG_BUCK5OUT		= 0x42,
> +	/* Reserved: 0x43 */
> +	MAX77802_REG_BUCK6CTRL		= 0x44,
> +	MAX77802_REG_BUCK6DVS1		= 0x45,
> +	MAX77802_REG_BUCK6DVS2		= 0x46,
> +	MAX77802_REG_BUCK6DVS3		= 0x47,
> +	MAX77802_REG_BUCK6DVS4		= 0x48,
> +	MAX77802_REG_BUCK6DVS5		= 0x49,
> +	MAX77802_REG_BUCK6DVS6		= 0x4A,
> +	MAX77802_REG_BUCK6DVS7		= 0x4B,
> +	MAX77802_REG_BUCK6DVS8		= 0x4C,
> +	/* Reserved: 0x4D */
> +	MAX77802_REG_BUCK7CTRL		= 0x4E,
> +	MAX77802_REG_BUCK7OUT		= 0x4F,
> +	/* Reserved: 0x50 */
> +	MAX77802_REG_BUCK8CTRL		= 0x51,
> +	MAX77802_REG_BUCK8OUT		= 0x52,
> +	/* Reserved: 0x53 */
> +	MAX77802_REG_BUCK9CTRL		= 0x54,
> +	MAX77802_REG_BUCK9OUT		= 0x55,
> +	/* Reserved: 0x56 */
> +	MAX77802_REG_BUCK10CTRL		= 0x57,
> +	MAX77802_REG_BUCK10OUT		= 0x58,
> +
> +	/* Reserved: 0x59-0x5F */
> +
> +	MAX77802_REG_LDO1CTRL1		= 0x60,
> +	MAX77802_REG_LDO2CTRL1		= 0x61,
> +	MAX77802_REG_LDO3CTRL1		= 0x62,
> +	MAX77802_REG_LDO4CTRL1		= 0x63,
> +	MAX77802_REG_LDO5CTRL1		= 0x64,
> +	MAX77802_REG_LDO6CTRL1		= 0x65,
> +	MAX77802_REG_LDO7CTRL1		= 0x66,
> +	MAX77802_REG_LDO8CTRL1		= 0x67,
> +	MAX77802_REG_LDO9CTRL1		= 0x68,
> +	MAX77802_REG_LDO10CTRL1		= 0x69,
> +	MAX77802_REG_LDO11CTRL1		= 0x6A,
> +	MAX77802_REG_LDO12CTRL1		= 0x6B,
> +	MAX77802_REG_LDO13CTRL1		= 0x6C,
> +	MAX77802_REG_LDO14CTRL1		= 0x6D,
> +	MAX77802_REG_LDO15CTRL1		= 0x6E,
> +	/* Reserved: 0x6F */
> +	MAX77802_REG_LDO17CTRL1		= 0x70,
> +	MAX77802_REG_LDO18CTRL1		= 0x71,
> +	MAX77802_REG_LDO19CTRL1		= 0x72,
> +	MAX77802_REG_LDO20CTRL1		= 0x73,
> +	MAX77802_REG_LDO21CTRL1		= 0x74,
> +	MAX77802_REG_LDO22CTRL1		= 0x75,
> +	MAX77802_REG_LDO23CTRL1		= 0x76,
> +	MAX77802_REG_LDO24CTRL1		= 0x77,
> +	MAX77802_REG_LDO25CTRL1		= 0x78,
> +	MAX77802_REG_LDO26CTRL1		= 0x79,
> +	MAX77802_REG_LDO27CTRL1		= 0x7A,
> +	MAX77802_REG_LDO28CTRL1		= 0x7B,
> +	MAX77802_REG_LDO29CTRL1		= 0x7C,
> +	MAX77802_REG_LDO30CTRL1		= 0x7D,
> +	/* Reserved: 0x7E */
> +	MAX77802_REG_LDO32CTRL1		= 0x7F,
> +	MAX77802_REG_LDO33CTRL1		= 0x80,
> +	MAX77802_REG_LDO34CTRL1		= 0x81,
> +	MAX77802_REG_LDO35CTRL1		= 0x82,
> +	/* Reserved: 0x83-0x8F */
> +	MAX77802_REG_LDO1CTRL2		= 0x90,
> +	MAX77802_REG_LDO2CTRL2		= 0x91,
> +	MAX77802_REG_LDO3CTRL2		= 0x92,
> +	MAX77802_REG_LDO4CTRL2		= 0x93,
> +	MAX77802_REG_LDO5CTRL2		= 0x94,
> +	MAX77802_REG_LDO6CTRL2		= 0x95,
> +	MAX77802_REG_LDO7CTRL2		= 0x96,
> +	MAX77802_REG_LDO8CTRL2		= 0x97,
> +	MAX77802_REG_LDO9CTRL2		= 0x98,
> +	MAX77802_REG_LDO10CTRL2		= 0x99,
> +	MAX77802_REG_LDO11CTRL2		= 0x9A,
> +	MAX77802_REG_LDO12CTRL2		= 0x9B,
> +	MAX77802_REG_LDO13CTRL2		= 0x9C,
> +	MAX77802_REG_LDO14CTRL2		= 0x9D,
> +	MAX77802_REG_LDO15CTRL2		= 0x9E,
> +	/* Reserved: 0x9F */
> +	MAX77802_REG_LDO17CTRL2		= 0xA0,
> +	MAX77802_REG_LDO18CTRL2		= 0xA1,
> +	MAX77802_REG_LDO19CTRL2		= 0xA2,
> +	MAX77802_REG_LDO20CTRL2		= 0xA3,
> +	MAX77802_REG_LDO21CTRL2		= 0xA4,
> +	MAX77802_REG_LDO22CTRL2		= 0xA5,
> +	MAX77802_REG_LDO23CTRL2		= 0xA6,
> +	MAX77802_REG_LDO24CTRL2		= 0xA7,
> +	MAX77802_REG_LDO25CTRL2		= 0xA8,
> +	MAX77802_REG_LDO26CTRL2		= 0xA9,
> +	MAX77802_REG_LDO27CTRL2		= 0xAA,
> +	MAX77802_REG_LDO28CTRL2		= 0xAB,
> +	MAX77802_REG_LDO29CTRL2		= 0xAC,
> +	MAX77802_REG_LDO30CTRL2		= 0xAD,
> +	/* Reserved: 0xAE */
> +	MAX77802_REG_LDO32CTRL2		= 0xAF,
> +	MAX77802_REG_LDO33CTRL2		= 0xB0,
> +	MAX77802_REG_LDO34CTRL2		= 0xB1,
> +	MAX77802_REG_LDO35CTRL2		= 0xB2,
> +	/* Reserved: 0xB3 */
> +
> +	MAX77802_REG_BBAT_CHG		= 0xB4,
> +	MAX77802_REG_32KHZ		= 0xB5,
> +
> +	MAX77802_REG_PMIC_END		= 0xB6,
> +};
> +
> +enum max77802_rtc_reg {
> +	MAX77802_RTC_INT		= 0xC0,
> +	MAX77802_RTC_INTM		= 0xC1,
> +	MAX77802_RTC_CONTROLM		= 0xC2,
> +	MAX77802_RTC_CONTROL		= 0xC3,
> +	MAX77802_RTC_UPDATE0		= 0xC4,
> +	MAX77802_RTC_UPDATE1		= 0xC5,
> +	MAX77802_WTSR_SMPL_CNTL		= 0xC6,
> +	MAX77802_RTC_SEC		= 0xC7,
> +	MAX77802_RTC_MIN		= 0xC8,
> +	MAX77802_RTC_HOUR		= 0xC9,
> +	MAX77802_RTC_WEEKDAY		= 0xCA,
> +	MAX77802_RTC_MONTH		= 0xCB,
> +	MAX77802_RTC_YEAR		= 0xCC,
> +	MAX77802_RTC_DATE		= 0xCD,
> +	MAX77802_RTC_AE1		= 0xCE,
> +	MAX77802_ALARM1_SEC		= 0xCF,
> +	MAX77802_ALARM1_MIN		= 0xD0,
> +	MAX77802_ALARM1_HOUR		= 0xD1,
> +	MAX77802_ALARM1_WEEKDAY		= 0xD2,
> +	MAX77802_ALARM1_MONTH		= 0xD3,
> +	MAX77802_ALARM1_YEAR		= 0xD4,
> +	MAX77802_ALARM1_DATE		= 0xD5,
> +	MAX77802_RTC_AE2		= 0xD6,
> +	MAX77802_ALARM2_SEC		= 0xD7,
> +	MAX77802_ALARM2_MIN		= 0xD8,
> +	MAX77802_ALARM2_HOUR		= 0xD9,
> +	MAX77802_ALARM2_WEEKDAY		= 0xDA,
> +	MAX77802_ALARM2_MONTH		= 0xDB,
> +	MAX77802_ALARM2_YEAR		= 0xDC,
> +	MAX77802_ALARM2_DATE		= 0xDD,
> +
> +	MAX77802_RTC_END		= 0xDF,
> +};
> +
> +#define MAX77802_IRQSRC_PMIC            (0)

Shouldn't it be BIT(0) or BIT(1)? It looks odd.

> +#define MAX77802_IRQSRC_RTC	        BIT(0)

Anyway, are these defines used anywhere? Seems not. 

Best regards,
Krzysztof

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

* Re: [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
  2014-06-25 19:03   ` Javier Martinez Canillas
@ 2014-06-26 10:08     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26 10:08 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
> (LDO) regulators. This patch adds support for all these regulators
> found on the MAX77802 PMIC and is based on a driver added by Simon
> Glass to the Chrome OS kernel 3.8 tree.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Set the supply_name for regulators to lookup their parent supply node.
>    Suggested by Mark Brown.
>  - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
>    Suggested by Doug Anderson.
> 
> Changes since v2:
>  - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
>  - Add a generic function to regmap core to copy registers instead of
>    having a driver-specific function. Suggested by Mark Brown.
>  - Remove unnecessary probe debug log. Suggested by Mark Brown.
>  - Set struct regulator_config dev field to MFD instead of the platform dev.
>    Suggested by Mark Brown.
>  - Read the regulators operational mode from the hardware registers instead
>    of setting to normal as default on probe. Suggested by Mark Brown.
>  - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.
> 
> Changes since v1:
>  - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
>  - Fix .set_suspend_mode handler comment and split regulators ops for
>    regulators that behave differently. Suggested by Mark Brown.
>  - Use module_platform_driver() instead of having init/exit functions.
>    Suggested by Mark Brown.
>  - Use the new descriptor-based GPIO interface instead of the deprecated
>    integer based GPIO one. Suggested by Mark Brown.
>  - Look for "regulators" child node instead of "voltage-regulators" to be
>    consistent with other PMIC drivers. Suggested by Mark Brown.

(...)

> +
> +static struct regulator_desc regulators[] = {
> +	regulator_77802_desc_16_buck(1),
> +	regulator_77802_desc_234_buck(2),
> +	regulator_77802_desc_234_buck(3),
> +	regulator_77802_desc_234_buck(4),
> +	regulator_77802_desc_buck5(5),
> +	regulator_77802_desc_16_buck(6),
> +	regulator_77802_desc_buck7_10(7),
> +	regulator_77802_desc_buck7_10(8),
> +	regulator_77802_desc_buck7_10(9),
> +	regulator_77802_desc_buck7_10(10),
> +	regulator_77802_desc_n_ldo(1, 10, 2),
> +	regulator_77802_desc_n_ldo(2, 10, 1),
> +	regulator_77802_desc_p_ldo(3, 3, 2),
> +	regulator_77802_desc_p_ldo(4, 6, 1),
> +	regulator_77802_desc_p_ldo(5, 3, 1),
> +	regulator_77802_desc_p_ldo(6, 3, 1),
> +	regulator_77802_desc_p_ldo(7, 3, 1),
> +	regulator_77802_desc_n_ldo(8, 1, 1),
> +	regulator_77802_desc_p_ldo(9, 5, 1),
> +	regulator_77802_desc_p_ldo(10, 4, 1),
> +	regulator_77802_desc_p_ldo(11, 4, 1),
> +	regulator_77802_desc_p_ldo(12, 9, 1),
> +	regulator_77802_desc_p_ldo(13, 4, 1),
> +	regulator_77802_desc_p_ldo(14, 4, 1),
> +	regulator_77802_desc_n_ldo(15, 1, 1),
> +	regulator_77802_desc_n_ldo(17, 2, 1),
> +	regulator_77802_desc_p_ldo(18, 7, 1),
> +	regulator_77802_desc_p_ldo(19, 5, 1),
> +	regulator_77802_desc_p_ldo(20, 7, 2),
> +	regulator_77802_desc_p_ldo(21, 6, 2),
> +	regulator_77802_desc_p_ldo(23, 9, 1),
> +	regulator_77802_desc_p_ldo(24, 6, 1),
> +	regulator_77802_desc_p_ldo(25, 9, 1),
> +	regulator_77802_desc_p_ldo(26, 9, 1),
> +	regulator_77802_desc_n_ldo(27, 2, 1),
> +	regulator_77802_desc_p_ldo(28, 7, 1),
> +	regulator_77802_desc_p_ldo(29, 7, 1),
> +	regulator_77802_desc_n_ldo(30, 2, 1),
> +	regulator_77802_desc_p_ldo(32, 9, 1),
> +	regulator_77802_desc_p_ldo(33, 6, 1),
> +	regulator_77802_desc_p_ldo(34, 9, 1),
> +	regulator_77802_desc_n_ldo(35, 2, 1),
> +};
> +
> +#ifdef CONFIG_OF
> +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
> +					struct max77802_platform_data *pdata)
> +{
> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> +	struct device_node *pmic_np, *regulators_np;
> +	struct max77802_regulator_data *rdata;
> +	struct of_regulator_match rmatch;
> +	unsigned int i;
> +
> +	pmic_np = iodev->dev->of_node;
> +	regulators_np = of_get_child_by_name(pmic_np, "regulators");
> +	if (!regulators_np) {
> +		dev_err(&pdev->dev, "could not find regulators sub-node\n");
> +		return -EINVAL;
> +	}
> +
> +	pdata->num_regulators = ARRAY_SIZE(regulators);
> +	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
> +			     pdata->num_regulators, GFP_KERNEL);
> +	if (!rdata) {
> +		of_node_put(regulators_np);
> +		return -ENOMEM;
> +	}
> +
> +	for (i = 0; i < pdata->num_regulators; i++) {
> +		rmatch.name = regulators[i].name;
> +		rmatch.init_data = NULL;
> +		rmatch.of_node = NULL;
> +		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
> +				       1) != 1) {
> +			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
> +				 rmatch.name);
> +			continue;
> +		}
> +		rdata[i].initdata = rmatch.init_data;
> +		rdata[i].of_node = rmatch.of_node;
> +		rdata[i].id = regulators[i].id;
> +	}

I think instead of matching one by one you can alternatively match
everything at once:

static struct of_regulator_match regulator_matches[] = {
	{ .name = "LDO1", },
	....
};

if (of_regulator_match(&pdev->dev, regulators_np, regulator_matches,
			ARRAY_SIZE(regulator_matches)) {

The code would be smaller although you would have to create an array
with names of regulators. I'll leave it up to you since I don't have
preference for it.

Best regards,
Krzysztof




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

* [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
@ 2014-06-26 10:08     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
> (LDO) regulators. This patch adds support for all these regulators
> found on the MAX77802 PMIC and is based on a driver added by Simon
> Glass to the Chrome OS kernel 3.8 tree.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Set the supply_name for regulators to lookup their parent supply node.
>    Suggested by Mark Brown.
>  - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
>    Suggested by Doug Anderson.
> 
> Changes since v2:
>  - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
>  - Add a generic function to regmap core to copy registers instead of
>    having a driver-specific function. Suggested by Mark Brown.
>  - Remove unnecessary probe debug log. Suggested by Mark Brown.
>  - Set struct regulator_config dev field to MFD instead of the platform dev.
>    Suggested by Mark Brown.
>  - Read the regulators operational mode from the hardware registers instead
>    of setting to normal as default on probe. Suggested by Mark Brown.
>  - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.
> 
> Changes since v1:
>  - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
>  - Fix .set_suspend_mode handler comment and split regulators ops for
>    regulators that behave differently. Suggested by Mark Brown.
>  - Use module_platform_driver() instead of having init/exit functions.
>    Suggested by Mark Brown.
>  - Use the new descriptor-based GPIO interface instead of the deprecated
>    integer based GPIO one. Suggested by Mark Brown.
>  - Look for "regulators" child node instead of "voltage-regulators" to be
>    consistent with other PMIC drivers. Suggested by Mark Brown.

(...)

> +
> +static struct regulator_desc regulators[] = {
> +	regulator_77802_desc_16_buck(1),
> +	regulator_77802_desc_234_buck(2),
> +	regulator_77802_desc_234_buck(3),
> +	regulator_77802_desc_234_buck(4),
> +	regulator_77802_desc_buck5(5),
> +	regulator_77802_desc_16_buck(6),
> +	regulator_77802_desc_buck7_10(7),
> +	regulator_77802_desc_buck7_10(8),
> +	regulator_77802_desc_buck7_10(9),
> +	regulator_77802_desc_buck7_10(10),
> +	regulator_77802_desc_n_ldo(1, 10, 2),
> +	regulator_77802_desc_n_ldo(2, 10, 1),
> +	regulator_77802_desc_p_ldo(3, 3, 2),
> +	regulator_77802_desc_p_ldo(4, 6, 1),
> +	regulator_77802_desc_p_ldo(5, 3, 1),
> +	regulator_77802_desc_p_ldo(6, 3, 1),
> +	regulator_77802_desc_p_ldo(7, 3, 1),
> +	regulator_77802_desc_n_ldo(8, 1, 1),
> +	regulator_77802_desc_p_ldo(9, 5, 1),
> +	regulator_77802_desc_p_ldo(10, 4, 1),
> +	regulator_77802_desc_p_ldo(11, 4, 1),
> +	regulator_77802_desc_p_ldo(12, 9, 1),
> +	regulator_77802_desc_p_ldo(13, 4, 1),
> +	regulator_77802_desc_p_ldo(14, 4, 1),
> +	regulator_77802_desc_n_ldo(15, 1, 1),
> +	regulator_77802_desc_n_ldo(17, 2, 1),
> +	regulator_77802_desc_p_ldo(18, 7, 1),
> +	regulator_77802_desc_p_ldo(19, 5, 1),
> +	regulator_77802_desc_p_ldo(20, 7, 2),
> +	regulator_77802_desc_p_ldo(21, 6, 2),
> +	regulator_77802_desc_p_ldo(23, 9, 1),
> +	regulator_77802_desc_p_ldo(24, 6, 1),
> +	regulator_77802_desc_p_ldo(25, 9, 1),
> +	regulator_77802_desc_p_ldo(26, 9, 1),
> +	regulator_77802_desc_n_ldo(27, 2, 1),
> +	regulator_77802_desc_p_ldo(28, 7, 1),
> +	regulator_77802_desc_p_ldo(29, 7, 1),
> +	regulator_77802_desc_n_ldo(30, 2, 1),
> +	regulator_77802_desc_p_ldo(32, 9, 1),
> +	regulator_77802_desc_p_ldo(33, 6, 1),
> +	regulator_77802_desc_p_ldo(34, 9, 1),
> +	regulator_77802_desc_n_ldo(35, 2, 1),
> +};
> +
> +#ifdef CONFIG_OF
> +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
> +					struct max77802_platform_data *pdata)
> +{
> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> +	struct device_node *pmic_np, *regulators_np;
> +	struct max77802_regulator_data *rdata;
> +	struct of_regulator_match rmatch;
> +	unsigned int i;
> +
> +	pmic_np = iodev->dev->of_node;
> +	regulators_np = of_get_child_by_name(pmic_np, "regulators");
> +	if (!regulators_np) {
> +		dev_err(&pdev->dev, "could not find regulators sub-node\n");
> +		return -EINVAL;
> +	}
> +
> +	pdata->num_regulators = ARRAY_SIZE(regulators);
> +	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
> +			     pdata->num_regulators, GFP_KERNEL);
> +	if (!rdata) {
> +		of_node_put(regulators_np);
> +		return -ENOMEM;
> +	}
> +
> +	for (i = 0; i < pdata->num_regulators; i++) {
> +		rmatch.name = regulators[i].name;
> +		rmatch.init_data = NULL;
> +		rmatch.of_node = NULL;
> +		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
> +				       1) != 1) {
> +			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
> +				 rmatch.name);
> +			continue;
> +		}
> +		rdata[i].initdata = rmatch.init_data;
> +		rdata[i].of_node = rmatch.of_node;
> +		rdata[i].id = regulators[i].id;
> +	}

I think instead of matching one by one you can alternatively match
everything at once:

static struct of_regulator_match regulator_matches[] = {
	{ .name = "LDO1", },
	....
};

if (of_regulator_match(&pdev->dev, regulators_np, regulator_matches,
			ARRAY_SIZE(regulator_matches)) {

The code would be smaller although you would have to create an array
with names of regulators. I'll leave it up to you since I don't have
preference for it.

Best regards,
Krzysztof

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

* Re: [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks
@ 2014-06-26 10:40     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26 10:40 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> The MAX77802 PMIC has two 32.768kHz Buffered Clock Outputs with
> Low Jitter Mode. This patch adds support for these two clocks.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3: None
> 
> Changes since v2: None
> 
> Changes since v1:
>  - Use module_platform_driver() instead of having init/exit functions.
>    Suggested by Mark Brown.
>  - Use the generic maxim clock driver to reduce code duplication with
>    clk-max77686.c driver.
> 
>  drivers/clk/Kconfig                        |  7 +++
>  drivers/clk/Makefile                       |  1 +
>  drivers/clk/clk-max77802.c                 | 99 ++++++++++++++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77802.h | 22 +++++++
>  4 files changed, 129 insertions(+)
>  create mode 100644 drivers/clk/clk-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h


Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof


> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 3fd4270..221260b 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -42,6 +42,13 @@ config COMMON_CLK_MAX77686
>  	---help---
>  	  This driver supports Maxim 77686 crystal oscillator clock. 
>  
> +config COMMON_CLK_MAX77802
> +	tristate "Clock driver for Maxim 77802 MFD"
> +	depends on MFD_MAX77802
> +	select COMMON_CLK_MAX_GEN
> +	---help---
> +	  This driver supports Maxim 77802 crystal oscillator clock.
> +
>  config COMMON_CLK_SI5351
>  	tristate "Clock driver for SiLabs 5351A/B/C"
>  	depends on I2C
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 6c1aff6..520ff76 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>  obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
>  obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
>  obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
> +obj-$(CONFIG_COMMON_CLK_MAX77802)	+= clk-max77802.o
>  obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
>  obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
>  obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
> diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
> new file mode 100644
> index 0000000..4253b44
> --- /dev/null
> +++ b/drivers/clk/clk-max77802.c
> @@ -0,0 +1,99 @@
> +/*
> + * clk-max77802.c - Clock driver for Maxim 77802
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * Copyright (C) 2012 Samsung Electornics
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on clk-max77686.c
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/max77802.h>
> +#include <linux/mfd/max77802-private.h>
> +#include <linux/clk-provider.h>
> +#include <linux/mutex.h>
> +#include <linux/clkdev.h>
> +
> +#include <dt-bindings/clock/maxim,max77802.h>
> +#include "clk-max-gen.h"
> +
> +#define MAX77802_CLOCK_OPMODE_MASK	0x1
> +#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
> +
> +static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
> +	[MAX77802_CLK_32K_AP] = {
> +		.name = "32khz_ap",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +	[MAX77802_CLK_32K_CP] = {
> +		.name = "32khz_cp",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +};
> +
> +static int max77802_clk_probe(struct platform_device *pdev)
> +{
> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> +	int ret;
> +
> +	ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
> +				max77802_clks_init, MAX77802_CLKS_NUM);
> +
> +	if (ret) {
> +		dev_err(&pdev->dev, "generic probe failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Enable low-jitter mode on the 32khz clocks. */
> +	ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
> +
> +	return ret;
> +}
> +
> +static int max77802_clk_remove(struct platform_device *pdev)
> +{
> +	return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
> +}
> +
> +static const struct platform_device_id max77802_clk_id[] = {
> +	{ "max77802-clk", 0},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(platform, max77802_clk_id);
> +
> +static struct platform_driver max77802_clk_driver = {
> +	.driver = {
> +		.name  = "max77802-clk",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = max77802_clk_probe,
> +	.remove = max77802_clk_remove,
> +	.id_table = max77802_clk_id,
> +};
> +
> +module_platform_driver(max77802_clk_driver);
> +
> +MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
> +MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
> new file mode 100644
> index 0000000..997312e
> --- /dev/null
> +++ b/include/dt-bindings/clock/maxim,max77802.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2014 Google, Inc
> + *
> + * 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.
> + *
> + * Device Tree binding constants clocks for the Maxim 77802 PMIC.
> + */
> +
> +#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +
> +/* Fixed rate clocks. */
> +
> +#define MAX77802_CLK_32K_AP		0
> +#define MAX77802_CLK_32K_CP		1
> +
> +/* Total number of clocks. */
> +#define MAX77802_CLKS_NUM		(MAX77802_CLK_32K_CP + 1)
> +
> +#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */


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

* Re: [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks
@ 2014-06-26 10:40     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26 10:40 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> The MAX77802 PMIC has two 32.768kHz Buffered Clock Outputs with
> Low Jitter Mode. This patch adds support for these two clocks.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez-ZGY8ohtN/8rSCDK34cm6iQ@public.gmane.org.uk>
> ---
> 
> Changes since v3: None
> 
> Changes since v2: None
> 
> Changes since v1:
>  - Use module_platform_driver() instead of having init/exit functions.
>    Suggested by Mark Brown.
>  - Use the generic maxim clock driver to reduce code duplication with
>    clk-max77686.c driver.
> 
>  drivers/clk/Kconfig                        |  7 +++
>  drivers/clk/Makefile                       |  1 +
>  drivers/clk/clk-max77802.c                 | 99 ++++++++++++++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77802.h | 22 +++++++
>  4 files changed, 129 insertions(+)
>  create mode 100644 drivers/clk/clk-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h


Reviewed-by: Krzysztof Kozlowski <k.kozlowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

Best regards,
Krzysztof


> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 3fd4270..221260b 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -42,6 +42,13 @@ config COMMON_CLK_MAX77686
>  	---help---
>  	  This driver supports Maxim 77686 crystal oscillator clock. 
>  
> +config COMMON_CLK_MAX77802
> +	tristate "Clock driver for Maxim 77802 MFD"
> +	depends on MFD_MAX77802
> +	select COMMON_CLK_MAX_GEN
> +	---help---
> +	  This driver supports Maxim 77802 crystal oscillator clock.
> +
>  config COMMON_CLK_SI5351
>  	tristate "Clock driver for SiLabs 5351A/B/C"
>  	depends on I2C
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 6c1aff6..520ff76 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>  obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
>  obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
>  obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
> +obj-$(CONFIG_COMMON_CLK_MAX77802)	+= clk-max77802.o
>  obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
>  obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
>  obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
> diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
> new file mode 100644
> index 0000000..4253b44
> --- /dev/null
> +++ b/drivers/clk/clk-max77802.c
> @@ -0,0 +1,99 @@
> +/*
> + * clk-max77802.c - Clock driver for Maxim 77802
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * Copyright (C) 2012 Samsung Electornics
> + * Jonghwa Lee <jonghwa3.lee-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on clk-max77686.c
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/max77802.h>
> +#include <linux/mfd/max77802-private.h>
> +#include <linux/clk-provider.h>
> +#include <linux/mutex.h>
> +#include <linux/clkdev.h>
> +
> +#include <dt-bindings/clock/maxim,max77802.h>
> +#include "clk-max-gen.h"
> +
> +#define MAX77802_CLOCK_OPMODE_MASK	0x1
> +#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
> +
> +static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
> +	[MAX77802_CLK_32K_AP] = {
> +		.name = "32khz_ap",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +	[MAX77802_CLK_32K_CP] = {
> +		.name = "32khz_cp",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +};
> +
> +static int max77802_clk_probe(struct platform_device *pdev)
> +{
> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> +	int ret;
> +
> +	ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
> +				max77802_clks_init, MAX77802_CLKS_NUM);
> +
> +	if (ret) {
> +		dev_err(&pdev->dev, "generic probe failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Enable low-jitter mode on the 32khz clocks. */
> +	ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
> +
> +	return ret;
> +}
> +
> +static int max77802_clk_remove(struct platform_device *pdev)
> +{
> +	return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
> +}
> +
> +static const struct platform_device_id max77802_clk_id[] = {
> +	{ "max77802-clk", 0},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(platform, max77802_clk_id);
> +
> +static struct platform_driver max77802_clk_driver = {
> +	.driver = {
> +		.name  = "max77802-clk",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = max77802_clk_probe,
> +	.remove = max77802_clk_remove,
> +	.id_table = max77802_clk_id,
> +};
> +
> +module_platform_driver(max77802_clk_driver);
> +
> +MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
> +MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
> new file mode 100644
> index 0000000..997312e
> --- /dev/null
> +++ b/include/dt-bindings/clock/maxim,max77802.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2014 Google, Inc
> + *
> + * 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.
> + *
> + * Device Tree binding constants clocks for the Maxim 77802 PMIC.
> + */
> +
> +#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +
> +/* Fixed rate clocks. */
> +
> +#define MAX77802_CLK_32K_AP		0
> +#define MAX77802_CLK_32K_CP		1
> +
> +/* Total number of clocks. */
> +#define MAX77802_CLKS_NUM		(MAX77802_CLK_32K_CP + 1)
> +
> +#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks
@ 2014-06-26 10:40     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 76+ messages in thread
From: Krzysztof Kozlowski @ 2014-06-26 10:40 UTC (permalink / raw)
  To: linux-arm-kernel

On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
> The MAX77802 PMIC has two 32.768kHz Buffered Clock Outputs with
> Low Jitter Mode. This patch adds support for these two clocks.
> 
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3: None
> 
> Changes since v2: None
> 
> Changes since v1:
>  - Use module_platform_driver() instead of having init/exit functions.
>    Suggested by Mark Brown.
>  - Use the generic maxim clock driver to reduce code duplication with
>    clk-max77686.c driver.
> 
>  drivers/clk/Kconfig                        |  7 +++
>  drivers/clk/Makefile                       |  1 +
>  drivers/clk/clk-max77802.c                 | 99 ++++++++++++++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77802.h | 22 +++++++
>  4 files changed, 129 insertions(+)
>  create mode 100644 drivers/clk/clk-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h


Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof


> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 3fd4270..221260b 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -42,6 +42,13 @@ config COMMON_CLK_MAX77686
>  	---help---
>  	  This driver supports Maxim 77686 crystal oscillator clock. 
>  
> +config COMMON_CLK_MAX77802
> +	tristate "Clock driver for Maxim 77802 MFD"
> +	depends on MFD_MAX77802
> +	select COMMON_CLK_MAX_GEN
> +	---help---
> +	  This driver supports Maxim 77802 crystal oscillator clock.
> +
>  config COMMON_CLK_SI5351
>  	tristate "Clock driver for SiLabs 5351A/B/C"
>  	depends on I2C
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 6c1aff6..520ff76 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>  obj-$(CONFIG_MACH_LOONGSON1)		+= clk-ls1x.o
>  obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
>  obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
> +obj-$(CONFIG_COMMON_CLK_MAX77802)	+= clk-max77802.o
>  obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
>  obj-$(CONFIG_ARCH_NOMADIK)		+= clk-nomadik.o
>  obj-$(CONFIG_ARCH_NSPIRE)		+= clk-nspire.o
> diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
> new file mode 100644
> index 0000000..4253b44
> --- /dev/null
> +++ b/drivers/clk/clk-max77802.c
> @@ -0,0 +1,99 @@
> +/*
> + * clk-max77802.c - Clock driver for Maxim 77802
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * Copyright (C) 2012 Samsung Electornics
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + * This driver is based on clk-max77686.c
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/max77802.h>
> +#include <linux/mfd/max77802-private.h>
> +#include <linux/clk-provider.h>
> +#include <linux/mutex.h>
> +#include <linux/clkdev.h>
> +
> +#include <dt-bindings/clock/maxim,max77802.h>
> +#include "clk-max-gen.h"
> +
> +#define MAX77802_CLOCK_OPMODE_MASK	0x1
> +#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
> +
> +static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
> +	[MAX77802_CLK_32K_AP] = {
> +		.name = "32khz_ap",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +	[MAX77802_CLK_32K_CP] = {
> +		.name = "32khz_cp",
> +		.ops = &max_gen_clk_ops,
> +		.flags = CLK_IS_ROOT,
> +	},
> +};
> +
> +static int max77802_clk_probe(struct platform_device *pdev)
> +{
> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
> +	int ret;
> +
> +	ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
> +				max77802_clks_init, MAX77802_CLKS_NUM);
> +
> +	if (ret) {
> +		dev_err(&pdev->dev, "generic probe failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Enable low-jitter mode on the 32khz clocks. */
> +	ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
> +				 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
> +
> +	return ret;
> +}
> +
> +static int max77802_clk_remove(struct platform_device *pdev)
> +{
> +	return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
> +}
> +
> +static const struct platform_device_id max77802_clk_id[] = {
> +	{ "max77802-clk", 0},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(platform, max77802_clk_id);
> +
> +static struct platform_driver max77802_clk_driver = {
> +	.driver = {
> +		.name  = "max77802-clk",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = max77802_clk_probe,
> +	.remove = max77802_clk_remove,
> +	.id_table = max77802_clk_id,
> +};
> +
> +module_platform_driver(max77802_clk_driver);
> +
> +MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
> +MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
> new file mode 100644
> index 0000000..997312e
> --- /dev/null
> +++ b/include/dt-bindings/clock/maxim,max77802.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2014 Google, Inc
> + *
> + * 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.
> + *
> + * Device Tree binding constants clocks for the Maxim 77802 PMIC.
> + */
> +
> +#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
> +
> +/* Fixed rate clocks. */
> +
> +#define MAX77802_CLK_32K_AP		0
> +#define MAX77802_CLK_32K_CP		1
> +
> +/* Total number of clocks. */
> +#define MAX77802_CLKS_NUM		(MAX77802_CLK_32K_CP + 1)
> +
> +#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-26  9:31     ` Krzysztof Kozlowski
@ 2014-06-26 11:13       ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 11:13 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hello Krzysztof,

Thanks a lot for your feedback.

On 06/26/2014 11:31 AM, Krzysztof Kozlowski wrote:
> Hi,
> 
> Just a few nit-picks below but overall everything looks fine:
> 
> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> 
> 

>> +
>> +static int max77802_i2c_probe(struct i2c_client *i2c,
>> +			      const struct i2c_device_id *id)
>> +{
>> +	struct max77802_dev *max77802 = NULL;
>> +	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
>> +	unsigned int data;
>> +	int ret = 0;
>> +
>> +	if (i2c->dev.of_node)
>> +		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
>> +
>> +	if (!pdata) {
>> +		dev_err(&i2c->dev, "No platform data found.\n");
>> +		return -EIO;
>> +	}
>> +
>> +	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
>> +				GFP_KERNEL);
>> +	if (max77802 == NULL)
> 
> It is inconsistent. Before you used "(!pd)" and "(!pdata)" so maybe
> stick to one format?
>

Right, I'll change to "(!max77802)" as well to be consistent.

>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int max77802_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>> +
>> +	if (device_may_wakeup(dev))
>> +		enable_irq_wake(max77802->irq);
>> +
>> +	disable_irq(max77802->irq);
> 
> Can you add short comment why this is needed? I know why but just for
> future generations which will wonder: "why do we need to disable the IRQ
> while suspending?" :). Especially that this is rather a workaround for
> issue in other driver (I2C bus).
>

Good idea, I'll add a comment here on next version so code archaeologists can
figure out what what's going on here.

>> +
>> +#define MAX77802_IRQSRC_PMIC            (0)
> 
> Shouldn't it be BIT(0) or BIT(1)? It looks odd.
> 
>> +#define MAX77802_IRQSRC_RTC	        BIT(0)
> 
> Anyway, are these defines used anywhere? Seems not. 
> 

Yes, these defines were used in the max77802-irq.c so is a left over from the
regmap IRQ chip refactoring. I'll remove these and also the ones from max77686
driver.

> Best regards,
> Krzysztof
> 
> 

Best regards
Javier

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 11:13       ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 11:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Krzysztof,

Thanks a lot for your feedback.

On 06/26/2014 11:31 AM, Krzysztof Kozlowski wrote:
> Hi,
> 
> Just a few nit-picks below but overall everything looks fine:
> 
> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> 
> 

>> +
>> +static int max77802_i2c_probe(struct i2c_client *i2c,
>> +			      const struct i2c_device_id *id)
>> +{
>> +	struct max77802_dev *max77802 = NULL;
>> +	struct max77802_platform_data *pdata = dev_get_platdata(&i2c->dev);
>> +	unsigned int data;
>> +	int ret = 0;
>> +
>> +	if (i2c->dev.of_node)
>> +		pdata = max77802_i2c_parse_dt_pdata(&i2c->dev);
>> +
>> +	if (!pdata) {
>> +		dev_err(&i2c->dev, "No platform data found.\n");
>> +		return -EIO;
>> +	}
>> +
>> +	max77802 = devm_kzalloc(&i2c->dev, sizeof(struct max77802_dev),
>> +				GFP_KERNEL);
>> +	if (max77802 == NULL)
> 
> It is inconsistent. Before you used "(!pd)" and "(!pdata)" so maybe
> stick to one format?
>

Right, I'll change to "(!max77802)" as well to be consistent.

>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int max77802_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>> +	struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>> +
>> +	if (device_may_wakeup(dev))
>> +		enable_irq_wake(max77802->irq);
>> +
>> +	disable_irq(max77802->irq);
> 
> Can you add short comment why this is needed? I know why but just for
> future generations which will wonder: "why do we need to disable the IRQ
> while suspending?" :). Especially that this is rather a workaround for
> issue in other driver (I2C bus).
>

Good idea, I'll add a comment here on next version so code archaeologists can
figure out what what's going on here.

>> +
>> +#define MAX77802_IRQSRC_PMIC            (0)
> 
> Shouldn't it be BIT(0) or BIT(1)? It looks odd.
> 
>> +#define MAX77802_IRQSRC_RTC	        BIT(0)
> 
> Anyway, are these defines used anywhere? Seems not. 
> 

Yes, these defines were used in the max77802-irq.c so is a left over from the
regmap IRQ chip refactoring. I'll remove these and also the ones from max77686
driver.

> Best regards,
> Krzysztof
> 
> 

Best regards
Javier

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

* Re: [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
  2014-06-26 10:08     ` Krzysztof Kozlowski
@ 2014-06-26 11:26       ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 11:26 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hello Krzysztof,

Thanks a lot for your feedback.

On 06/26/2014 12:08 PM, Krzysztof Kozlowski wrote:
> On śro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
>> The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
>> (LDO) regulators. This patch adds support for all these regulators
>> found on the MAX77802 PMIC and is based on a driver added by Simon
>> Glass to the Chrome OS kernel 3.8 tree.
>> 
>> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> ---
>> 
>> Changes since v3:
>>  - Set the supply_name for regulators to lookup their parent supply node.
>>    Suggested by Mark Brown.
>>  - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
>>    Suggested by Doug Anderson.
>> 
>> Changes since v2:
>>  - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
>>  - Add a generic function to regmap core to copy registers instead of
>>    having a driver-specific function. Suggested by Mark Brown.
>>  - Remove unnecessary probe debug log. Suggested by Mark Brown.
>>  - Set struct regulator_config dev field to MFD instead of the platform dev.
>>    Suggested by Mark Brown.
>>  - Read the regulators operational mode from the hardware registers instead
>>    of setting to normal as default on probe. Suggested by Mark Brown.
>>  - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.
>> 
>> Changes since v1:
>>  - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
>>  - Fix .set_suspend_mode handler comment and split regulators ops for
>>    regulators that behave differently. Suggested by Mark Brown.
>>  - Use module_platform_driver() instead of having init/exit functions.
>>    Suggested by Mark Brown.
>>  - Use the new descriptor-based GPIO interface instead of the deprecated
>>    integer based GPIO one. Suggested by Mark Brown.
>>  - Look for "regulators" child node instead of "voltage-regulators" to be
>>    consistent with other PMIC drivers. Suggested by Mark Brown.
> 
> (...)
> 
>> +
>> +#ifdef CONFIG_OF
>> +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
>> +					struct max77802_platform_data *pdata)
>> +{
>> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
>> +	struct device_node *pmic_np, *regulators_np;
>> +	struct max77802_regulator_data *rdata;
>> +	struct of_regulator_match rmatch;
>> +	unsigned int i;
>> +
>> +	pmic_np = iodev->dev->of_node;
>> +	regulators_np = of_get_child_by_name(pmic_np, "regulators");
>> +	if (!regulators_np) {
>> +		dev_err(&pdev->dev, "could not find regulators sub-node\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	pdata->num_regulators = ARRAY_SIZE(regulators);
>> +	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
>> +			     pdata->num_regulators, GFP_KERNEL);
>> +	if (!rdata) {
>> +		of_node_put(regulators_np);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	for (i = 0; i < pdata->num_regulators; i++) {
>> +		rmatch.name = regulators[i].name;
>> +		rmatch.init_data = NULL;
>> +		rmatch.of_node = NULL;
>> +		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
>> +				       1) != 1) {
>> +			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
>> +				 rmatch.name);
>> +			continue;
>> +		}
>> +		rdata[i].initdata = rmatch.init_data;
>> +		rdata[i].of_node = rmatch.of_node;
>> +		rdata[i].id = regulators[i].id;
>> +	}
> 
> I think instead of matching one by one you can alternatively match
> everything at once:
> 
> static struct of_regulator_match regulator_matches[] = {
> 	{ .name = "LDO1", },
> 	....
> };
> 
> if (of_regulator_match(&pdev->dev, regulators_np, regulator_matches,
> 			ARRAY_SIZE(regulator_matches)) {
> 
> The code would be smaller although you would have to create an array
> with names of regulators. I'll leave it up to you since I don't have
> preference for it.
>

It's true that the code will be smaller and even more efficient by passing an
array of struct of_regulator_match instad but as you said I'll have to add
yet-another-table with duplicates information that is already present in the
struct regulator_desc regulators[] array.

That's why I prefer the code as it right now since I think that there are just
too many data structures in this driver. But I don't mind to use the other
approach though if you think that it's better.

> Best regards,
> Krzysztof
> 
> 
> 
> 

Best regards,
Javier

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

* [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators
@ 2014-06-26 11:26       ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Krzysztof,

Thanks a lot for your feedback.

On 06/26/2014 12:08 PM, Krzysztof Kozlowski wrote:
> On ?ro, 2014-06-25 at 21:03 +0200, Javier Martinez Canillas wrote:
>> The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout
>> (LDO) regulators. This patch adds support for all these regulators
>> found on the MAX77802 PMIC and is based on a driver added by Simon
>> Glass to the Chrome OS kernel 3.8 tree.
>> 
>> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> ---
>> 
>> Changes since v3:
>>  - Set the supply_name for regulators to lookup their parent supply node.
>>    Suggested by Mark Brown.
>>  - Change Exyno5 for Exynos5420/Exynos5800 in regulator driver Kconfig.
>>    Suggested by Doug Anderson.
>> 
>> Changes since v2:
>>  - Use dev_warn() instead pr_warn(). Suggested by Mark Brown.
>>  - Add a generic function to regmap core to copy registers instead of
>>    having a driver-specific function. Suggested by Mark Brown.
>>  - Remove unnecessary probe debug log. Suggested by Mark Brown.
>>  - Set struct regulator_config dev field to MFD instead of the platform dev.
>>    Suggested by Mark Brown.
>>  - Read the regulators operational mode from the hardware registers instead
>>    of setting to normal as default on probe. Suggested by Mark Brown.
>>  - Remove unnecessary cross-subsystem dependencies. Suggested by Lee Jones.
>> 
>> Changes since v1:
>>  - Remove unneeded check if num_regulators != MAX77802_MAX_REGULATORS.
>>  - Fix .set_suspend_mode handler comment and split regulators ops for
>>    regulators that behave differently. Suggested by Mark Brown.
>>  - Use module_platform_driver() instead of having init/exit functions.
>>    Suggested by Mark Brown.
>>  - Use the new descriptor-based GPIO interface instead of the deprecated
>>    integer based GPIO one. Suggested by Mark Brown.
>>  - Look for "regulators" child node instead of "voltage-regulators" to be
>>    consistent with other PMIC drivers. Suggested by Mark Brown.
> 
> (...)
> 
>> +
>> +#ifdef CONFIG_OF
>> +static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
>> +					struct max77802_platform_data *pdata)
>> +{
>> +	struct max77802_dev *iodev = dev_get_drvdata(pdev->dev.parent);
>> +	struct device_node *pmic_np, *regulators_np;
>> +	struct max77802_regulator_data *rdata;
>> +	struct of_regulator_match rmatch;
>> +	unsigned int i;
>> +
>> +	pmic_np = iodev->dev->of_node;
>> +	regulators_np = of_get_child_by_name(pmic_np, "regulators");
>> +	if (!regulators_np) {
>> +		dev_err(&pdev->dev, "could not find regulators sub-node\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	pdata->num_regulators = ARRAY_SIZE(regulators);
>> +	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
>> +			     pdata->num_regulators, GFP_KERNEL);
>> +	if (!rdata) {
>> +		of_node_put(regulators_np);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	for (i = 0; i < pdata->num_regulators; i++) {
>> +		rmatch.name = regulators[i].name;
>> +		rmatch.init_data = NULL;
>> +		rmatch.of_node = NULL;
>> +		if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
>> +				       1) != 1) {
>> +			dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
>> +				 rmatch.name);
>> +			continue;
>> +		}
>> +		rdata[i].initdata = rmatch.init_data;
>> +		rdata[i].of_node = rmatch.of_node;
>> +		rdata[i].id = regulators[i].id;
>> +	}
> 
> I think instead of matching one by one you can alternatively match
> everything at once:
> 
> static struct of_regulator_match regulator_matches[] = {
> 	{ .name = "LDO1", },
> 	....
> };
> 
> if (of_regulator_match(&pdev->dev, regulators_np, regulator_matches,
> 			ARRAY_SIZE(regulator_matches)) {
> 
> The code would be smaller although you would have to create an array
> with names of regulators. I'll leave it up to you since I don't have
> preference for it.
>

It's true that the code will be smaller and even more efficient by passing an
array of struct of_regulator_match instad but as you said I'll have to add
yet-another-table with duplicates information that is already present in the
struct regulator_desc regulators[] array.

That's why I prefer the code as it right now since I think that there are just
too many data structures in this driver. But I don't mind to use the other
approach though if you think that it's better.

> Best regards,
> Krzysztof
> 
> 
> 
> 

Best regards,
Javier

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

* Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
  2014-06-25 19:03   ` Javier Martinez Canillas
  (?)
@ 2014-06-26 11:51     ` Yadwinder Singh Brar
  -1 siblings, 0 replies; 76+ messages in thread
From: Yadwinder Singh Brar @ 2014-06-26 11:51 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hi Javier,

Sorry for jumping in late, but just one concern mentioned inline.

[ .. ]

> +
> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       return 32768;
> +}

Isn't more safer(correct), if it check and return 0 when clk is
disabled(unprepared) ?

Regards,
Yadwinder

> +
> +struct clk_ops max_gen_clk_ops = {
> +       .prepare        = max_gen_clk_prepare,
> +       .unprepare      = max_gen_clk_unprepare,
> +       .is_prepared    = max_gen_clk_is_prepared,
> +       .recalc_rate    = max_gen_recalc_rate,
> +};
> +EXPORT_SYMBOL_GPL(max_gen_clk_ops);
> +
> +static struct clk *max_gen_clk_register(struct device *dev,
> +                                       struct max_gen_clk *max_gen)
> +{
> +       struct clk *clk;
> +       struct clk_hw *hw = &max_gen->hw;
> +
> +       clk = clk_register(dev, hw);
> +       if (IS_ERR(clk))
> +               return clk;
> +
> +       max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
> +       if (!max_gen->lookup)
> +               return ERR_PTR(-ENOMEM);
> +
> +       max_gen->lookup->con_id = hw->init->name;
> +       max_gen->lookup->clk = clk;
> +
> +       clkdev_add(max_gen->lookup);
> +
> +       return clk;
> +}
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init)
> +{
> +       int i, ret;
> +       struct max_gen_clk *max_gen_clks;
> +       struct clk **clocks;
> +       struct device *dev = &pdev->dev;
> +
> +       clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
> +       if (!clocks)
> +               return -ENOMEM;
> +
> +       max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
> +                                   * num_init, GFP_KERNEL);
> +       if (!max_gen_clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < num_init; i++) {
> +               max_gen_clks[i].regmap = regmap;
> +               max_gen_clks[i].mask = 1 << i;
> +               max_gen_clks[i].reg = reg;
> +               max_gen_clks[i].hw.init = &clks_init[i];
> +
> +               clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
> +               if (IS_ERR(clocks[i])) {
> +                       ret = PTR_ERR(clocks[i]);
> +                       dev_err(dev, "failed to register %s\n",
> +                               max_gen_clks[i].hw.init->name);
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       platform_set_drvdata(pdev, clocks);
> +
> +       if (dev->of_node) {
> +               struct clk_onecell_data *of_data;
> +
> +               of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
> +               if (!of_data) {
> +                       ret = -ENOMEM;
> +                       goto err_clocks;
> +               }
> +
> +               of_data->clks = clocks;
> +               of_data->clk_num = num_init;
> +               ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> +                                         of_data);
> +
> +               if (ret) {
> +                       dev_err(dev, "failed to register OF clock provider\n");
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       return 0;
> +
> +err_clocks:
> +       for (--i; i >= 0; --i) {
> +               clkdev_drop(max_gen_clks[i].lookup);
> +               clk_unregister(max_gen_clks[i].hw.clk);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_probe);
> +
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init)
> +{
> +       struct clk **clocks = platform_get_drvdata(pdev);
> +       struct device *dev = pdev->dev.parent;
> +       int i;
> +
> +       if (dev->of_node)
> +               of_clk_del_provider(dev->of_node);
> +
> +       for (i = 0; i < num_init; i++) {
> +               struct clk_hw *hw = __clk_get_hw(clocks[i]);
> +               struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +               clkdev_drop(max_gen->lookup);
> +               clk_unregister(clocks[i]);
> +       }
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_remove);
> diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
> new file mode 100644
> index 0000000..997e86f
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.h
> @@ -0,0 +1,32 @@
> +/*
> + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __CLK_MAX_GEN_H__
> +#define __CLK_MAX_GEN_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/clkdev.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init);
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init);
> +extern struct clk_ops max_gen_clk_ops;
> +
> +#endif /* __CLK_MAX_GEN_H__ */
> --
> 2.0.0.rc2
>
> --
> 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] 76+ messages in thread

* Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-26 11:51     ` Yadwinder Singh Brar
  0 siblings, 0 replies; 76+ messages in thread
From: Yadwinder Singh Brar @ 2014-06-26 11:51 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hi Javier,

Sorry for jumping in late, but just one concern mentioned inline.

[ .. ]

> +
> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       return 32768;
> +}

Isn't more safer(correct), if it check and return 0 when clk is
disabled(unprepared) ?

Regards,
Yadwinder

> +
> +struct clk_ops max_gen_clk_ops = {
> +       .prepare        = max_gen_clk_prepare,
> +       .unprepare      = max_gen_clk_unprepare,
> +       .is_prepared    = max_gen_clk_is_prepared,
> +       .recalc_rate    = max_gen_recalc_rate,
> +};
> +EXPORT_SYMBOL_GPL(max_gen_clk_ops);
> +
> +static struct clk *max_gen_clk_register(struct device *dev,
> +                                       struct max_gen_clk *max_gen)
> +{
> +       struct clk *clk;
> +       struct clk_hw *hw = &max_gen->hw;
> +
> +       clk = clk_register(dev, hw);
> +       if (IS_ERR(clk))
> +               return clk;
> +
> +       max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
> +       if (!max_gen->lookup)
> +               return ERR_PTR(-ENOMEM);
> +
> +       max_gen->lookup->con_id = hw->init->name;
> +       max_gen->lookup->clk = clk;
> +
> +       clkdev_add(max_gen->lookup);
> +
> +       return clk;
> +}
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init)
> +{
> +       int i, ret;
> +       struct max_gen_clk *max_gen_clks;
> +       struct clk **clocks;
> +       struct device *dev = &pdev->dev;
> +
> +       clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
> +       if (!clocks)
> +               return -ENOMEM;
> +
> +       max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
> +                                   * num_init, GFP_KERNEL);
> +       if (!max_gen_clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < num_init; i++) {
> +               max_gen_clks[i].regmap = regmap;
> +               max_gen_clks[i].mask = 1 << i;
> +               max_gen_clks[i].reg = reg;
> +               max_gen_clks[i].hw.init = &clks_init[i];
> +
> +               clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
> +               if (IS_ERR(clocks[i])) {
> +                       ret = PTR_ERR(clocks[i]);
> +                       dev_err(dev, "failed to register %s\n",
> +                               max_gen_clks[i].hw.init->name);
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       platform_set_drvdata(pdev, clocks);
> +
> +       if (dev->of_node) {
> +               struct clk_onecell_data *of_data;
> +
> +               of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
> +               if (!of_data) {
> +                       ret = -ENOMEM;
> +                       goto err_clocks;
> +               }
> +
> +               of_data->clks = clocks;
> +               of_data->clk_num = num_init;
> +               ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> +                                         of_data);
> +
> +               if (ret) {
> +                       dev_err(dev, "failed to register OF clock provider\n");
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       return 0;
> +
> +err_clocks:
> +       for (--i; i >= 0; --i) {
> +               clkdev_drop(max_gen_clks[i].lookup);
> +               clk_unregister(max_gen_clks[i].hw.clk);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_probe);
> +
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init)
> +{
> +       struct clk **clocks = platform_get_drvdata(pdev);
> +       struct device *dev = pdev->dev.parent;
> +       int i;
> +
> +       if (dev->of_node)
> +               of_clk_del_provider(dev->of_node);
> +
> +       for (i = 0; i < num_init; i++) {
> +               struct clk_hw *hw = __clk_get_hw(clocks[i]);
> +               struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +               clkdev_drop(max_gen->lookup);
> +               clk_unregister(clocks[i]);
> +       }
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_remove);
> diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
> new file mode 100644
> index 0000000..997e86f
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.h
> @@ -0,0 +1,32 @@
> +/*
> + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __CLK_MAX_GEN_H__
> +#define __CLK_MAX_GEN_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/clkdev.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init);
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init);
> +extern struct clk_ops max_gen_clk_ops;
> +
> +#endif /* __CLK_MAX_GEN_H__ */
> --
> 2.0.0.rc2
>
> --
> 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] 76+ messages in thread

* [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-26 11:51     ` Yadwinder Singh Brar
  0 siblings, 0 replies; 76+ messages in thread
From: Yadwinder Singh Brar @ 2014-06-26 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Javier,

Sorry for jumping in late, but just one concern mentioned inline.

[ .. ]

> +
> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       return 32768;
> +}

Isn't more safer(correct), if it check and return 0 when clk is
disabled(unprepared) ?

Regards,
Yadwinder

> +
> +struct clk_ops max_gen_clk_ops = {
> +       .prepare        = max_gen_clk_prepare,
> +       .unprepare      = max_gen_clk_unprepare,
> +       .is_prepared    = max_gen_clk_is_prepared,
> +       .recalc_rate    = max_gen_recalc_rate,
> +};
> +EXPORT_SYMBOL_GPL(max_gen_clk_ops);
> +
> +static struct clk *max_gen_clk_register(struct device *dev,
> +                                       struct max_gen_clk *max_gen)
> +{
> +       struct clk *clk;
> +       struct clk_hw *hw = &max_gen->hw;
> +
> +       clk = clk_register(dev, hw);
> +       if (IS_ERR(clk))
> +               return clk;
> +
> +       max_gen->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
> +       if (!max_gen->lookup)
> +               return ERR_PTR(-ENOMEM);
> +
> +       max_gen->lookup->con_id = hw->init->name;
> +       max_gen->lookup->clk = clk;
> +
> +       clkdev_add(max_gen->lookup);
> +
> +       return clk;
> +}
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init)
> +{
> +       int i, ret;
> +       struct max_gen_clk *max_gen_clks;
> +       struct clk **clocks;
> +       struct device *dev = &pdev->dev;
> +
> +       clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
> +       if (!clocks)
> +               return -ENOMEM;
> +
> +       max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
> +                                   * num_init, GFP_KERNEL);
> +       if (!max_gen_clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < num_init; i++) {
> +               max_gen_clks[i].regmap = regmap;
> +               max_gen_clks[i].mask = 1 << i;
> +               max_gen_clks[i].reg = reg;
> +               max_gen_clks[i].hw.init = &clks_init[i];
> +
> +               clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
> +               if (IS_ERR(clocks[i])) {
> +                       ret = PTR_ERR(clocks[i]);
> +                       dev_err(dev, "failed to register %s\n",
> +                               max_gen_clks[i].hw.init->name);
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       platform_set_drvdata(pdev, clocks);
> +
> +       if (dev->of_node) {
> +               struct clk_onecell_data *of_data;
> +
> +               of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
> +               if (!of_data) {
> +                       ret = -ENOMEM;
> +                       goto err_clocks;
> +               }
> +
> +               of_data->clks = clocks;
> +               of_data->clk_num = num_init;
> +               ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> +                                         of_data);
> +
> +               if (ret) {
> +                       dev_err(dev, "failed to register OF clock provider\n");
> +                       goto err_clocks;
> +               }
> +       }
> +
> +       return 0;
> +
> +err_clocks:
> +       for (--i; i >= 0; --i) {
> +               clkdev_drop(max_gen_clks[i].lookup);
> +               clk_unregister(max_gen_clks[i].hw.clk);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_probe);
> +
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init)
> +{
> +       struct clk **clocks = platform_get_drvdata(pdev);
> +       struct device *dev = pdev->dev.parent;
> +       int i;
> +
> +       if (dev->of_node)
> +               of_clk_del_provider(dev->of_node);
> +
> +       for (i = 0; i < num_init; i++) {
> +               struct clk_hw *hw = __clk_get_hw(clocks[i]);
> +               struct max_gen_clk *max_gen = to_max_gen_clk(hw);
> +
> +               clkdev_drop(max_gen->lookup);
> +               clk_unregister(clocks[i]);
> +       }
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(max_gen_clk_remove);
> diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
> new file mode 100644
> index 0000000..997e86f
> --- /dev/null
> +++ b/drivers/clk/clk-max-gen.h
> @@ -0,0 +1,32 @@
> +/*
> + * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
> + *
> + * Copyright (C) 2014 Google, Inc
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __CLK_MAX_GEN_H__
> +#define __CLK_MAX_GEN_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/clkdev.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +
> +int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
> +                     u32 reg, struct clk_init_data *clks_init, int num_init);
> +int max_gen_clk_remove(struct platform_device *pdev, int num_init);
> +extern struct clk_ops max_gen_clk_ops;
> +
> +#endif /* __CLK_MAX_GEN_H__ */
> --
> 2.0.0.rc2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
  2014-06-26 11:51     ` Yadwinder Singh Brar
  (?)
@ 2014-06-26 12:31       ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 12:31 UTC (permalink / raw)
  To: Yadwinder Singh Brar
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hello Yadwinder,

Thanks a lot for your feedback.

On 06/26/2014 01:51 PM, Yadwinder Singh Brar wrote:
> Hi Javier,
> 
> Sorry for jumping in late, but just one concern mentioned inline.
> 
> [ .. ]
> 
>> +
>> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
>> +                                        unsigned long parent_rate)
>> +{
>> +       return 32768;
>> +}
> 
> Isn't more safer(correct), if it check and return 0 when clk is
> disabled(unprepared) ?
> 

Makes sense to me. I'll add a if (__clk_is_enabled(hw->clk)) check in the next
version.

> Regards,
> Yadwinder
> 

Best regards,
Javier

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

* Re: [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-26 12:31       ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 12:31 UTC (permalink / raw)
  To: Yadwinder Singh Brar
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hello Yadwinder,

Thanks a lot for your feedback.

On 06/26/2014 01:51 PM, Yadwinder Singh Brar wrote:
> Hi Javier,
> 
> Sorry for jumping in late, but just one concern mentioned inline.
> 
> [ .. ]
> 
>> +
>> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
>> +                                        unsigned long parent_rate)
>> +{
>> +       return 32768;
>> +}
> 
> Isn't more safer(correct), if it check and return 0 when clk is
> disabled(unprepared) ?
> 

Makes sense to me. I'll add a if (__clk_is_enabled(hw->clk)) check in the next
version.

> Regards,
> Yadwinder
> 

Best regards,
Javier

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

* [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks
@ 2014-06-26 12:31       ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 12:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Yadwinder,

Thanks a lot for your feedback.

On 06/26/2014 01:51 PM, Yadwinder Singh Brar wrote:
> Hi Javier,
> 
> Sorry for jumping in late, but just one concern mentioned inline.
> 
> [ .. ]
> 
>> +
>> +static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
>> +                                        unsigned long parent_rate)
>> +{
>> +       return 32768;
>> +}
> 
> Isn't more safer(correct), if it check and return 0 when clk is
> disabled(unprepared) ?
> 

Makes sense to me. I'll add a if (__clk_is_enabled(hw->clk)) check in the next
version.

> Regards,
> Yadwinder
> 

Best regards,
Javier

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

* Re: [PATCH v4 00/14] Add Maxim 77802 PMIC support
  2014-06-25 19:03 ` Javier Martinez Canillas
  (?)
@ 2014-06-26 13:32   ` Naveen Krishna Ch
  -1 siblings, 0 replies; 76+ messages in thread
From: Naveen Krishna Ch @ 2014-06-26 13:32 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hello Javier,

On 26 June 2014 00:33, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
> a Real-Time-Clock (RTC) and a I2C interface to program the individual
> regulators, clocks and the RTC.
>
> This fourth version of the patch-set addresses several issues pointed
> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
> changes are added on each patch change log.
>
> This series are based on drivers added by Simon Glass to the Chrome OS
> kernel and adds support for the Maxim 77802 Power Management IC, their
> regulators, clocks, RTC and I2C interface.
>
> NOTE: This version of the series model the real power scheme for Maxim
> 77802 regulators instead of a simplistic model like in older versions.
> So these changes depend on patch:
>
> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
> https://patchwork.kernel.org/patch/4411351/
>
> which adds tps65090 support to Peach boards since regulators from this
> PMIC supply power to a set of MAX77802 regulators.
>
> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
> pit (max77802) Chromebooks and it's composed of the following patches:
>
> Doug Anderson (1):
>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>
> Javier Martinez Canillas (13):
>   mfd: max77686: Convert to use regmap_irq
>   clk: max77686: Add DT include for MAX77686 PMIC clock
>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>   clk: Add generic driver for Maxim PMIC clocks
>   clk: max77686: Convert to the generic max clock driver
>   mfd: Add driver for Maxim 77802 Power Management IC
>   mfd: max77802: Add DT binding documentation
>   regmap: Add regmap_reg_copy function
>   regulator: Add driver for Maxim 77802 PMIC regulators
>   clk: Add driver for Maxim 77802 PMIC clocks
>   clk: max77802: Add DT binding documentation
>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>
>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>  drivers/base/regmap/regmap.c                       |  34 +
>  drivers/clk/Kconfig                                |  11 +
>  drivers/clk/Makefile                               |   2 +
>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>  drivers/clk/clk-max-gen.h                          |  32 +
>  drivers/clk/clk-max77686.c                         | 183 +-----
>  drivers/clk/clk-max77802.c                         |  99 +++
>  drivers/mfd/Kconfig                                |  15 +
>  drivers/mfd/Makefile                               |   3 +-
>  drivers/mfd/max77686-irq.c                         | 319 ----------
>  drivers/mfd/max77686.c                             |  97 ++-
>  drivers/mfd/max77802.c                             | 366 +++++++++++
>  drivers/regulator/Kconfig                          |   9 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>  drivers/rtc/Kconfig                                |  10 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-max77686.c                         |  55 +-
>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>  include/linux/mfd/max77686-private.h               |  28 +-
>  include/linux/mfd/max77686.h                       |   2 -
>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>  include/linux/mfd/max77802.h                       | 121 ++++
>  include/linux/regmap.h                             |   9 +
>  31 files changed, 3583 insertions(+), 532 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>  create mode 100644 drivers/clk/clk-max-gen.c
>  create mode 100644 drivers/clk/clk-max-gen.h
>  create mode 100644 drivers/clk/clk-max77802.c
>  delete mode 100644 drivers/mfd/max77686-irq.c
>  create mode 100644 drivers/mfd/max77802.c
>  create mode 100644 drivers/regulator/max77802.c
>  create mode 100644 drivers/rtc/rtc-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>  create mode 100644 include/linux/mfd/max77802-private.h
>  create mode 100644 include/linux/mfd/max77802.h
>
> --
> 2.0.0.rc2
> --
> 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

With this patchset
+
[PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
+
spi: s3c64xx: fix broken "cs_gpios" usage in the driver
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
+
[PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
http://www.gossamer-threads.com/lists/linux/kernel/1951591

Tested on Peach PIT and PI boards.

1. Max77802 seems to probe and configure the supplies properly.
    Verified via the sysfs entries exported by the regulators.

2. ADC probes fine and Thermistors report proper values,
    ADC requires vdd_supply = "ldo09_reg".

Tested-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>

-- 
Shine bright,
(: Nav :)

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

* Re: [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-26 13:32   ` Naveen Krishna Ch
  0 siblings, 0 replies; 76+ messages in thread
From: Naveen Krishna Ch @ 2014-06-26 13:32 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel

Hello Javier,

On 26 June 2014 00:33, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
> a Real-Time-Clock (RTC) and a I2C interface to program the individual
> regulators, clocks and the RTC.
>
> This fourth version of the patch-set addresses several issues pointed
> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
> changes are added on each patch change log.
>
> This series are based on drivers added by Simon Glass to the Chrome OS
> kernel and adds support for the Maxim 77802 Power Management IC, their
> regulators, clocks, RTC and I2C interface.
>
> NOTE: This version of the series model the real power scheme for Maxim
> 77802 regulators instead of a simplistic model like in older versions.
> So these changes depend on patch:
>
> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
> https://patchwork.kernel.org/patch/4411351/
>
> which adds tps65090 support to Peach boards since regulators from this
> PMIC supply power to a set of MAX77802 regulators.
>
> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
> pit (max77802) Chromebooks and it's composed of the following patches:
>
> Doug Anderson (1):
>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>
> Javier Martinez Canillas (13):
>   mfd: max77686: Convert to use regmap_irq
>   clk: max77686: Add DT include for MAX77686 PMIC clock
>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>   clk: Add generic driver for Maxim PMIC clocks
>   clk: max77686: Convert to the generic max clock driver
>   mfd: Add driver for Maxim 77802 Power Management IC
>   mfd: max77802: Add DT binding documentation
>   regmap: Add regmap_reg_copy function
>   regulator: Add driver for Maxim 77802 PMIC regulators
>   clk: Add driver for Maxim 77802 PMIC clocks
>   clk: max77802: Add DT binding documentation
>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>
>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>  drivers/base/regmap/regmap.c                       |  34 +
>  drivers/clk/Kconfig                                |  11 +
>  drivers/clk/Makefile                               |   2 +
>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>  drivers/clk/clk-max-gen.h                          |  32 +
>  drivers/clk/clk-max77686.c                         | 183 +-----
>  drivers/clk/clk-max77802.c                         |  99 +++
>  drivers/mfd/Kconfig                                |  15 +
>  drivers/mfd/Makefile                               |   3 +-
>  drivers/mfd/max77686-irq.c                         | 319 ----------
>  drivers/mfd/max77686.c                             |  97 ++-
>  drivers/mfd/max77802.c                             | 366 +++++++++++
>  drivers/regulator/Kconfig                          |   9 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>  drivers/rtc/Kconfig                                |  10 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-max77686.c                         |  55 +-
>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>  include/linux/mfd/max77686-private.h               |  28 +-
>  include/linux/mfd/max77686.h                       |   2 -
>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>  include/linux/mfd/max77802.h                       | 121 ++++
>  include/linux/regmap.h                             |   9 +
>  31 files changed, 3583 insertions(+), 532 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>  create mode 100644 drivers/clk/clk-max-gen.c
>  create mode 100644 drivers/clk/clk-max-gen.h
>  create mode 100644 drivers/clk/clk-max77802.c
>  delete mode 100644 drivers/mfd/max77686-irq.c
>  create mode 100644 drivers/mfd/max77802.c
>  create mode 100644 drivers/regulator/max77802.c
>  create mode 100644 drivers/rtc/rtc-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>  create mode 100644 include/linux/mfd/max77802-private.h
>  create mode 100644 include/linux/mfd/max77802.h
>
> --
> 2.0.0.rc2
> --
> 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

With this patchset
+
[PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
+
spi: s3c64xx: fix broken "cs_gpios" usage in the driver
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
+
[PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
http://www.gossamer-threads.com/lists/linux/kernel/1951591

Tested on Peach PIT and PI boards.

1. Max77802 seems to probe and configure the supplies properly.
    Verified via the sysfs entries exported by the regulators.

2. ADC probes fine and Thermistors report proper values,
    ADC requires vdd_supply = "ldo09_reg".

Tested-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>

-- 
Shine bright,
(: Nav :)

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

* [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-26 13:32   ` Naveen Krishna Ch
  0 siblings, 0 replies; 76+ messages in thread
From: Naveen Krishna Ch @ 2014-06-26 13:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Javier,

On 26 June 2014 00:33, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
> a Real-Time-Clock (RTC) and a I2C interface to program the individual
> regulators, clocks and the RTC.
>
> This fourth version of the patch-set addresses several issues pointed
> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
> changes are added on each patch change log.
>
> This series are based on drivers added by Simon Glass to the Chrome OS
> kernel and adds support for the Maxim 77802 Power Management IC, their
> regulators, clocks, RTC and I2C interface.
>
> NOTE: This version of the series model the real power scheme for Maxim
> 77802 regulators instead of a simplistic model like in older versions.
> So these changes depend on patch:
>
> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
> https://patchwork.kernel.org/patch/4411351/
>
> which adds tps65090 support to Peach boards since regulators from this
> PMIC supply power to a set of MAX77802 regulators.
>
> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
> pit (max77802) Chromebooks and it's composed of the following patches:
>
> Doug Anderson (1):
>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>
> Javier Martinez Canillas (13):
>   mfd: max77686: Convert to use regmap_irq
>   clk: max77686: Add DT include for MAX77686 PMIC clock
>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>   clk: Add generic driver for Maxim PMIC clocks
>   clk: max77686: Convert to the generic max clock driver
>   mfd: Add driver for Maxim 77802 Power Management IC
>   mfd: max77802: Add DT binding documentation
>   regmap: Add regmap_reg_copy function
>   regulator: Add driver for Maxim 77802 PMIC regulators
>   clk: Add driver for Maxim 77802 PMIC clocks
>   clk: max77802: Add DT binding documentation
>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>
>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>  drivers/base/regmap/regmap.c                       |  34 +
>  drivers/clk/Kconfig                                |  11 +
>  drivers/clk/Makefile                               |   2 +
>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>  drivers/clk/clk-max-gen.h                          |  32 +
>  drivers/clk/clk-max77686.c                         | 183 +-----
>  drivers/clk/clk-max77802.c                         |  99 +++
>  drivers/mfd/Kconfig                                |  15 +
>  drivers/mfd/Makefile                               |   3 +-
>  drivers/mfd/max77686-irq.c                         | 319 ----------
>  drivers/mfd/max77686.c                             |  97 ++-
>  drivers/mfd/max77802.c                             | 366 +++++++++++
>  drivers/regulator/Kconfig                          |   9 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>  drivers/rtc/Kconfig                                |  10 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-max77686.c                         |  55 +-
>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>  include/linux/mfd/max77686-private.h               |  28 +-
>  include/linux/mfd/max77686.h                       |   2 -
>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>  include/linux/mfd/max77802.h                       | 121 ++++
>  include/linux/regmap.h                             |   9 +
>  31 files changed, 3583 insertions(+), 532 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>  create mode 100644 drivers/clk/clk-max-gen.c
>  create mode 100644 drivers/clk/clk-max-gen.h
>  create mode 100644 drivers/clk/clk-max77802.c
>  delete mode 100644 drivers/mfd/max77686-irq.c
>  create mode 100644 drivers/mfd/max77802.c
>  create mode 100644 drivers/regulator/max77802.c
>  create mode 100644 drivers/rtc/rtc-max77802.c
>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>  create mode 100644 include/linux/mfd/max77802-private.h
>  create mode 100644 include/linux/mfd/max77802.h
>
> --
> 2.0.0.rc2
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

With this patchset
+
[PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
+
spi: s3c64xx: fix broken "cs_gpios" usage in the driver
http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
+
[PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
http://www.gossamer-threads.com/lists/linux/kernel/1951591

Tested on Peach PIT and PI boards.

1. Max77802 seems to probe and configure the supplies properly.
    Verified via the sysfs entries exported by the regulators.

2. ADC probes fine and Thermistors report proper values,
    ADC requires vdd_supply = "ldo09_reg".

Tested-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>

-- 
Shine bright,
(: Nav :)

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

* Re: [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-26 13:56     ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 13:56 UTC (permalink / raw)
  To: Naveen Krishna Ch
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski, linux-arm-kernel, devicetree,
	linux-samsung-soc, linux-kernel, Yadwinder Singh Brar

Hello Naveen,

Thanks a lot for testing!

On 06/26/2014 03:32 PM, Naveen Krishna Ch wrote:
> Hello Javier,
> 
> On 26 June 2014 00:33, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
>> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
>> a Real-Time-Clock (RTC) and a I2C interface to program the individual
>> regulators, clocks and the RTC.
>>
>> This fourth version of the patch-set addresses several issues pointed
>> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
>> changes are added on each patch change log.
>>
>> This series are based on drivers added by Simon Glass to the Chrome OS
>> kernel and adds support for the Maxim 77802 Power Management IC, their
>> regulators, clocks, RTC and I2C interface.
>>
>> NOTE: This version of the series model the real power scheme for Maxim
>> 77802 regulators instead of a simplistic model like in older versions.
>> So these changes depend on patch:
>>
>> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
>> https://patchwork.kernel.org/patch/4411351/
>>
>> which adds tps65090 support to Peach boards since regulators from this
>> PMIC supply power to a set of MAX77802 regulators.
>>
>> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
>> pit (max77802) Chromebooks and it's composed of the following patches:
>>
>> Doug Anderson (1):
>>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>>
>> Javier Martinez Canillas (13):
>>   mfd: max77686: Convert to use regmap_irq
>>   clk: max77686: Add DT include for MAX77686 PMIC clock
>>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>>   clk: Add generic driver for Maxim PMIC clocks
>>   clk: max77686: Convert to the generic max clock driver
>>   mfd: Add driver for Maxim 77802 Power Management IC
>>   mfd: max77802: Add DT binding documentation
>>   regmap: Add regmap_reg_copy function
>>   regulator: Add driver for Maxim 77802 PMIC regulators
>>   clk: Add driver for Maxim 77802 PMIC clocks
>>   clk: max77802: Add DT binding documentation
>>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>>
>>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>>  drivers/base/regmap/regmap.c                       |  34 +
>>  drivers/clk/Kconfig                                |  11 +
>>  drivers/clk/Makefile                               |   2 +
>>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>>  drivers/clk/clk-max-gen.h                          |  32 +
>>  drivers/clk/clk-max77686.c                         | 183 +-----
>>  drivers/clk/clk-max77802.c                         |  99 +++
>>  drivers/mfd/Kconfig                                |  15 +
>>  drivers/mfd/Makefile                               |   3 +-
>>  drivers/mfd/max77686-irq.c                         | 319 ----------
>>  drivers/mfd/max77686.c                             |  97 ++-
>>  drivers/mfd/max77802.c                             | 366 +++++++++++
>>  drivers/regulator/Kconfig                          |   9 +
>>  drivers/regulator/Makefile                         |   1 +
>>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>>  drivers/rtc/Kconfig                                |  10 +
>>  drivers/rtc/Makefile                               |   1 +
>>  drivers/rtc/rtc-max77686.c                         |  55 +-
>>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>>  include/linux/mfd/max77686-private.h               |  28 +-
>>  include/linux/mfd/max77686.h                       |   2 -
>>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>>  include/linux/mfd/max77802.h                       | 121 ++++
>>  include/linux/regmap.h                             |   9 +
>>  31 files changed, 3583 insertions(+), 532 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>>  create mode 100644 drivers/clk/clk-max-gen.c
>>  create mode 100644 drivers/clk/clk-max-gen.h
>>  create mode 100644 drivers/clk/clk-max77802.c
>>  delete mode 100644 drivers/mfd/max77686-irq.c
>>  create mode 100644 drivers/mfd/max77802.c
>>  create mode 100644 drivers/regulator/max77802.c
>>  create mode 100644 drivers/rtc/rtc-max77802.c
>>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>>  create mode 100644 include/linux/mfd/max77802-private.h
>>  create mode 100644 include/linux/mfd/max77802.h
>>
>> --
>> 2.0.0.rc2
>> --
>> 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
> 
> With this patchset
> +
> [PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
> http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
> +
> spi: s3c64xx: fix broken "cs_gpios" usage in the driver
> http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
> +
> [PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
> http://www.gossamer-threads.com/lists/linux/kernel/1951591
> 
> Tested on Peach PIT and PI boards.
> 
> 1. Max77802 seems to probe and configure the supplies properly.
>     Verified via the sysfs entries exported by the regulators.
> 
> 2. ADC probes fine and Thermistors report proper values,
>     ADC requires vdd_supply = "ldo09_reg".
> 
> Tested-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
> 

I'll post another version today which addresses some minor nits suggested by
Krzysztof Kozlowski and Yadwinder Singh Brar.

will add your Tested-by tag to the patches in the series related to max77802
related patches and Peach Pit/Pi.

Best regards,
Javier

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

* Re: [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-26 13:56     ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 13:56 UTC (permalink / raw)
  To: Naveen Krishna Ch
  Cc: Lee Jones, Samuel Ortiz, Mark Brown, Mike Turquette,
	Liam Girdwood, Alessandro Zummo, Kukjin Kim, Doug Anderson,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	Krzysztof Kozlowski,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Yadwinder Singh Brar

Hello Naveen,

Thanks a lot for testing!

On 06/26/2014 03:32 PM, Naveen Krishna Ch wrote:
> Hello Javier,
> 
> On 26 June 2014 00:33, Javier Martinez Canillas
> <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org> wrote:
>> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
>> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
>> a Real-Time-Clock (RTC) and a I2C interface to program the individual
>> regulators, clocks and the RTC.
>>
>> This fourth version of the patch-set addresses several issues pointed
>> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
>> changes are added on each patch change log.
>>
>> This series are based on drivers added by Simon Glass to the Chrome OS
>> kernel and adds support for the Maxim 77802 Power Management IC, their
>> regulators, clocks, RTC and I2C interface.
>>
>> NOTE: This version of the series model the real power scheme for Maxim
>> 77802 regulators instead of a simplistic model like in older versions.
>> So these changes depend on patch:
>>
>> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
>> https://patchwork.kernel.org/patch/4411351/
>>
>> which adds tps65090 support to Peach boards since regulators from this
>> PMIC supply power to a set of MAX77802 regulators.
>>
>> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
>> pit (max77802) Chromebooks and it's composed of the following patches:
>>
>> Doug Anderson (1):
>>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>>
>> Javier Martinez Canillas (13):
>>   mfd: max77686: Convert to use regmap_irq
>>   clk: max77686: Add DT include for MAX77686 PMIC clock
>>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>>   clk: Add generic driver for Maxim PMIC clocks
>>   clk: max77686: Convert to the generic max clock driver
>>   mfd: Add driver for Maxim 77802 Power Management IC
>>   mfd: max77802: Add DT binding documentation
>>   regmap: Add regmap_reg_copy function
>>   regulator: Add driver for Maxim 77802 PMIC regulators
>>   clk: Add driver for Maxim 77802 PMIC clocks
>>   clk: max77802: Add DT binding documentation
>>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>>
>>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>>  drivers/base/regmap/regmap.c                       |  34 +
>>  drivers/clk/Kconfig                                |  11 +
>>  drivers/clk/Makefile                               |   2 +
>>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>>  drivers/clk/clk-max-gen.h                          |  32 +
>>  drivers/clk/clk-max77686.c                         | 183 +-----
>>  drivers/clk/clk-max77802.c                         |  99 +++
>>  drivers/mfd/Kconfig                                |  15 +
>>  drivers/mfd/Makefile                               |   3 +-
>>  drivers/mfd/max77686-irq.c                         | 319 ----------
>>  drivers/mfd/max77686.c                             |  97 ++-
>>  drivers/mfd/max77802.c                             | 366 +++++++++++
>>  drivers/regulator/Kconfig                          |   9 +
>>  drivers/regulator/Makefile                         |   1 +
>>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>>  drivers/rtc/Kconfig                                |  10 +
>>  drivers/rtc/Makefile                               |   1 +
>>  drivers/rtc/rtc-max77686.c                         |  55 +-
>>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>>  include/linux/mfd/max77686-private.h               |  28 +-
>>  include/linux/mfd/max77686.h                       |   2 -
>>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>>  include/linux/mfd/max77802.h                       | 121 ++++
>>  include/linux/regmap.h                             |   9 +
>>  31 files changed, 3583 insertions(+), 532 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>>  create mode 100644 drivers/clk/clk-max-gen.c
>>  create mode 100644 drivers/clk/clk-max-gen.h
>>  create mode 100644 drivers/clk/clk-max77802.c
>>  delete mode 100644 drivers/mfd/max77686-irq.c
>>  create mode 100644 drivers/mfd/max77802.c
>>  create mode 100644 drivers/regulator/max77802.c
>>  create mode 100644 drivers/rtc/rtc-max77802.c
>>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>>  create mode 100644 include/linux/mfd/max77802-private.h
>>  create mode 100644 include/linux/mfd/max77802.h
>>
>> --
>> 2.0.0.rc2
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> With this patchset
> +
> [PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
> http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
> +
> spi: s3c64xx: fix broken "cs_gpios" usage in the driver
> http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
> +
> [PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
> http://www.gossamer-threads.com/lists/linux/kernel/1951591
> 
> Tested on Peach PIT and PI boards.
> 
> 1. Max77802 seems to probe and configure the supplies properly.
>     Verified via the sysfs entries exported by the regulators.
> 
> 2. ADC probes fine and Thermistors report proper values,
>     ADC requires vdd_supply = "ldo09_reg".
> 
> Tested-by: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> 

I'll post another version today which addresses some minor nits suggested by
Krzysztof Kozlowski and Yadwinder Singh Brar.

will add your Tested-by tag to the patches in the series related to max77802
related patches and Peach Pit/Pi.

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 00/14] Add Maxim 77802 PMIC support
@ 2014-06-26 13:56     ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 13:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Naveen,

Thanks a lot for testing!

On 06/26/2014 03:32 PM, Naveen Krishna Ch wrote:
> Hello Javier,
> 
> On 26 June 2014 00:33, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>> MAX77802 is a PMIC that contains 10 high efficiency Buck regulators,
>> 32 Low-dropout (LDO) regulators, two 32kHz buffered clock outputs,
>> a Real-Time-Clock (RTC) and a I2C interface to program the individual
>> regulators, clocks and the RTC.
>>
>> This fourth version of the patch-set addresses several issues pointed
>> out by Mark Brown, Doug Anderson and Krzysztof Kozlowski The individual
>> changes are added on each patch change log.
>>
>> This series are based on drivers added by Simon Glass to the Chrome OS
>> kernel and adds support for the Maxim 77802 Power Management IC, their
>> regulators, clocks, RTC and I2C interface.
>>
>> NOTE: This version of the series model the real power scheme for Maxim
>> 77802 regulators instead of a simplistic model like in older versions.
>> So these changes depend on patch:
>>
>> "[PATCH v3] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi"
>> https://patchwork.kernel.org/patch/4411351/
>>
>> which adds tps65090 support to Peach boards since regulators from this
>> PMIC supply power to a set of MAX77802 regulators.
>>
>> The patch-set has been tested on both Daisy/Snow (max77686) and Peach
>> pit (max77802) Chromebooks and it's composed of the following patches:
>>
>> Doug Anderson (1):
>>   mfd: max77686: Allow the max77686 rtc to wakeup the system
>>
>> Javier Martinez Canillas (13):
>>   mfd: max77686: Convert to use regmap_irq
>>   clk: max77686: Add DT include for MAX77686 PMIC clock
>>   clk: max77686: Improve Maxim 77686 PMIC clocks binding
>>   clk: Add generic driver for Maxim PMIC clocks
>>   clk: max77686: Convert to the generic max clock driver
>>   mfd: Add driver for Maxim 77802 Power Management IC
>>   mfd: max77802: Add DT binding documentation
>>   regmap: Add regmap_reg_copy function
>>   regulator: Add driver for Maxim 77802 PMIC regulators
>>   clk: Add driver for Maxim 77802 PMIC clocks
>>   clk: max77802: Add DT binding documentation
>>   rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock
>>   ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi
>>
>>  .../devicetree/bindings/clock/maxim,max77686.txt   |  15 +-
>>  .../devicetree/bindings/clock/maxim,max77802.txt   |  42 ++
>>  Documentation/devicetree/bindings/mfd/max77802.txt |  97 +++
>>  arch/arm/boot/dts/exynos5420-peach-pit.dts         | 343 ++++++++++
>>  arch/arm/boot/dts/exynos5800-peach-pi.dts          | 343 ++++++++++
>>  drivers/base/regmap/regmap.c                       |  34 +
>>  drivers/clk/Kconfig                                |  11 +
>>  drivers/clk/Makefile                               |   2 +
>>  drivers/clk/clk-max-gen.c                          | 195 ++++++
>>  drivers/clk/clk-max-gen.h                          |  32 +
>>  drivers/clk/clk-max77686.c                         | 183 +-----
>>  drivers/clk/clk-max77802.c                         |  99 +++
>>  drivers/mfd/Kconfig                                |  15 +
>>  drivers/mfd/Makefile                               |   3 +-
>>  drivers/mfd/max77686-irq.c                         | 319 ----------
>>  drivers/mfd/max77686.c                             |  97 ++-
>>  drivers/mfd/max77802.c                             | 366 +++++++++++
>>  drivers/regulator/Kconfig                          |   9 +
>>  drivers/regulator/Makefile                         |   1 +
>>  drivers/regulator/max77802.c                       | 694 +++++++++++++++++++++
>>  drivers/rtc/Kconfig                                |  10 +
>>  drivers/rtc/Makefile                               |   1 +
>>  drivers/rtc/rtc-max77686.c                         |  55 +-
>>  drivers/rtc/rtc-max77802.c                         | 637 +++++++++++++++++++
>>  include/dt-bindings/clock/maxim,max77686.h         |  23 +
>>  include/dt-bindings/clock/maxim,max77802.h         |  22 +
>>  include/linux/mfd/max77686-private.h               |  28 +-
>>  include/linux/mfd/max77686.h                       |   2 -
>>  include/linux/mfd/max77802-private.h               | 307 +++++++++
>>  include/linux/mfd/max77802.h                       | 121 ++++
>>  include/linux/regmap.h                             |   9 +
>>  31 files changed, 3583 insertions(+), 532 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max77802.txt
>>  create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt
>>  create mode 100644 drivers/clk/clk-max-gen.c
>>  create mode 100644 drivers/clk/clk-max-gen.h
>>  create mode 100644 drivers/clk/clk-max77802.c
>>  delete mode 100644 drivers/mfd/max77686-irq.c
>>  create mode 100644 drivers/mfd/max77802.c
>>  create mode 100644 drivers/regulator/max77802.c
>>  create mode 100644 drivers/rtc/rtc-max77802.c
>>  create mode 100644 include/dt-bindings/clock/maxim,max77686.h
>>  create mode 100644 include/dt-bindings/clock/maxim,max77802.h
>>  create mode 100644 include/linux/mfd/max77802-private.h
>>  create mode 100644 include/linux/mfd/max77802.h
>>
>> --
>> 2.0.0.rc2
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> With this patchset
> +
> [PATCH 0/4 v2] hwmon: ntc_thermistor: prepose vendor prefix change
> http://www.spinics.net/lists/linux-samsung-soc/msg33034.html
> +
> spi: s3c64xx: fix broken "cs_gpios" usage in the driver
> http://comments.gmane.org/gmane.linux.kernel.samsung-soc/33102
> +
> [PATCH v2] ARM: dts: Add cros_ec to exynos5420-peach-pit and exynos5800-peach-pi
> http://www.gossamer-threads.com/lists/linux/kernel/1951591
> 
> Tested on Peach PIT and PI boards.
> 
> 1. Max77802 seems to probe and configure the supplies properly.
>     Verified via the sysfs entries exported by the regulators.
> 
> 2. ADC probes fine and Thermistors report proper values,
>     ADC requires vdd_supply = "ldo09_reg".
> 
> Tested-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
> 

I'll post another version today which addresses some minor nits suggested by
Krzysztof Kozlowski and Yadwinder Singh Brar.

will add your Tested-by tag to the patches in the series related to max77802
related patches and Peach Pit/Pi.

Best regards,
Javier

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-26 11:13       ` Javier Martinez Canillas
  (?)
@ 2014-06-26 16:12         ` Doug Anderson
  -1 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:12 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int max77802_suspend(struct device *dev)
>>> +{
>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>> +
>>> +    if (device_may_wakeup(dev))
>>> +            enable_irq_wake(max77802->irq);
>>> +
>>> +    disable_irq(max77802->irq);
>>
>> Can you add short comment why this is needed? I know why but just for
>> future generations which will wonder: "why do we need to disable the IRQ
>> while suspending?" :). Especially that this is rather a workaround for
>> issue in other driver (I2C bus).
>>
>
> Good idea, I'll add a comment here on next version so code archaeologists can
> figure out what what's going on here.

Is the disable_irq() needed if you have
<https://patchwork.kernel.org/patch/4421891/>?

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:12         ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:12 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int max77802_suspend(struct device *dev)
>>> +{
>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>> +
>>> +    if (device_may_wakeup(dev))
>>> +            enable_irq_wake(max77802->irq);
>>> +
>>> +    disable_irq(max77802->irq);
>>
>> Can you add short comment why this is needed? I know why but just for
>> future generations which will wonder: "why do we need to disable the IRQ
>> while suspending?" :). Especially that this is rather a workaround for
>> issue in other driver (I2C bus).
>>
>
> Good idea, I'll add a comment here on next version so code archaeologists can
> figure out what what's going on here.

Is the disable_irq() needed if you have
<https://patchwork.kernel.org/patch/4421891/>?

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:12         ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:12 UTC (permalink / raw)
  To: linux-arm-kernel

Javier,

On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int max77802_suspend(struct device *dev)
>>> +{
>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>> +
>>> +    if (device_may_wakeup(dev))
>>> +            enable_irq_wake(max77802->irq);
>>> +
>>> +    disable_irq(max77802->irq);
>>
>> Can you add short comment why this is needed? I know why but just for
>> future generations which will wonder: "why do we need to disable the IRQ
>> while suspending?" :). Especially that this is rather a workaround for
>> issue in other driver (I2C bus).
>>
>
> Good idea, I'll add a comment here on next version so code archaeologists can
> figure out what what's going on here.

Is the disable_irq() needed if you have
<https://patchwork.kernel.org/patch/4421891/>?

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:18           ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:18 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hello Doug,

On 06/26/2014 06:12 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int max77802_suspend(struct device *dev)
>>>> +{
>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>> +
>>>> +    if (device_may_wakeup(dev))
>>>> +            enable_irq_wake(max77802->irq);
>>>> +
>>>> +    disable_irq(max77802->irq);
>>>
>>> Can you add short comment why this is needed? I know why but just for
>>> future generations which will wonder: "why do we need to disable the IRQ
>>> while suspending?" :). Especially that this is rather a workaround for
>>> issue in other driver (I2C bus).
>>>
>>
>> Good idea, I'll add a comment here on next version so code archaeologists can
>> figure out what what's going on here.
> 
> Is the disable_irq() needed if you have
> <https://patchwork.kernel.org/patch/4421891/>?
> 

Probably not but I added the following comment:

	/*
	 * The IRQ must be disabled during suspend since due wakeup
	 * ordering issues it may be possible that the I2C controller
	 * is still suspended when the interrupt happens so the IRQ
	 * handler will fail to read the I2C bus.
	 */
	disable_irq(max77802->irq);

since in theory this PMIC can be used in other SoCs besides
Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
these other SoCs may not resume at noirq time.

But on a second thought, this PMIC seems to be designed specially for these two
Exynos SoCs so I guess it's safe to assume that it is not needed?

Best regards,
Javier

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:18           ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:18 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, linux-samsung-soc,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hello Doug,

On 06/26/2014 06:12 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
> <javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org> wrote:
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int max77802_suspend(struct device *dev)
>>>> +{
>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>> +
>>>> +    if (device_may_wakeup(dev))
>>>> +            enable_irq_wake(max77802->irq);
>>>> +
>>>> +    disable_irq(max77802->irq);
>>>
>>> Can you add short comment why this is needed? I know why but just for
>>> future generations which will wonder: "why do we need to disable the IRQ
>>> while suspending?" :). Especially that this is rather a workaround for
>>> issue in other driver (I2C bus).
>>>
>>
>> Good idea, I'll add a comment here on next version so code archaeologists can
>> figure out what what's going on here.
> 
> Is the disable_irq() needed if you have
> <https://patchwork.kernel.org/patch/4421891/>?
> 

Probably not but I added the following comment:

	/*
	 * The IRQ must be disabled during suspend since due wakeup
	 * ordering issues it may be possible that the I2C controller
	 * is still suspended when the interrupt happens so the IRQ
	 * handler will fail to read the I2C bus.
	 */
	disable_irq(max77802->irq);

since in theory this PMIC can be used in other SoCs besides
Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
these other SoCs may not resume at noirq time.

But on a second thought, this PMIC seems to be designed specially for these two
Exynos SoCs so I guess it's safe to assume that it is not needed?

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:18           ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Doug,

On 06/26/2014 06:12 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int max77802_suspend(struct device *dev)
>>>> +{
>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>> +
>>>> +    if (device_may_wakeup(dev))
>>>> +            enable_irq_wake(max77802->irq);
>>>> +
>>>> +    disable_irq(max77802->irq);
>>>
>>> Can you add short comment why this is needed? I know why but just for
>>> future generations which will wonder: "why do we need to disable the IRQ
>>> while suspending?" :). Especially that this is rather a workaround for
>>> issue in other driver (I2C bus).
>>>
>>
>> Good idea, I'll add a comment here on next version so code archaeologists can
>> figure out what what's going on here.
> 
> Is the disable_irq() needed if you have
> <https://patchwork.kernel.org/patch/4421891/>?
> 

Probably not but I added the following comment:

	/*
	 * The IRQ must be disabled during suspend since due wakeup
	 * ordering issues it may be possible that the I2C controller
	 * is still suspended when the interrupt happens so the IRQ
	 * handler will fail to read the I2C bus.
	 */
	disable_irq(max77802->irq);

since in theory this PMIC can be used in other SoCs besides
Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
these other SoCs may not resume at noirq time.

But on a second thought, this PMIC seems to be designed specially for these two
Exynos SoCs so I guess it's safe to assume that it is not needed?

Best regards,
Javier

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-26 16:18           ` Javier Martinez Canillas
  (?)
@ 2014-06-26 16:29             ` Doug Anderson
  -1 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:29 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Hello Doug,
>
> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>> Javier,
>>
>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>> <javier.martinez@collabora.co.uk> wrote:
>>>>> +
>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>> +static int max77802_suspend(struct device *dev)
>>>>> +{
>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>> +
>>>>> +    if (device_may_wakeup(dev))
>>>>> +            enable_irq_wake(max77802->irq);
>>>>> +
>>>>> +    disable_irq(max77802->irq);
>>>>
>>>> Can you add short comment why this is needed? I know why but just for
>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>> while suspending?" :). Especially that this is rather a workaround for
>>>> issue in other driver (I2C bus).
>>>>
>>>
>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>> figure out what what's going on here.
>>
>> Is the disable_irq() needed if you have
>> <https://patchwork.kernel.org/patch/4421891/>?
>>
>
> Probably not but I added the following comment:
>
>         /*
>          * The IRQ must be disabled during suspend since due wakeup
>          * ordering issues it may be possible that the I2C controller
>          * is still suspended when the interrupt happens so the IRQ
>          * handler will fail to read the I2C bus.
>          */
>         disable_irq(max77802->irq);
>
> since in theory this PMIC can be used in other SoCs besides
> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
> these other SoCs may not resume at noirq time.
>
> But on a second thought, this PMIC seems to be designed specially for these two
> Exynos SoCs so I guess it's safe to assume that it is not needed?

Right, there's a close coupling between PMICs and SoCs.  The PMIC has
special sequencing and default voltage levels that were tuned exactly
for this SoC.

Note: Wolfram has not actually responded to my patch much less
accepted it.  It's entirely possible that in another month or two
we'll hear back a big fat NAK.  In that case your solution will be the
best one I can think of.


-Doug

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:29             ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:29 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Javier,

On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Hello Doug,
>
> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>> Javier,
>>
>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>> <javier.martinez@collabora.co.uk> wrote:
>>>>> +
>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>> +static int max77802_suspend(struct device *dev)
>>>>> +{
>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>> +
>>>>> +    if (device_may_wakeup(dev))
>>>>> +            enable_irq_wake(max77802->irq);
>>>>> +
>>>>> +    disable_irq(max77802->irq);
>>>>
>>>> Can you add short comment why this is needed? I know why but just for
>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>> while suspending?" :). Especially that this is rather a workaround for
>>>> issue in other driver (I2C bus).
>>>>
>>>
>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>> figure out what what's going on here.
>>
>> Is the disable_irq() needed if you have
>> <https://patchwork.kernel.org/patch/4421891/>?
>>
>
> Probably not but I added the following comment:
>
>         /*
>          * The IRQ must be disabled during suspend since due wakeup
>          * ordering issues it may be possible that the I2C controller
>          * is still suspended when the interrupt happens so the IRQ
>          * handler will fail to read the I2C bus.
>          */
>         disable_irq(max77802->irq);
>
> since in theory this PMIC can be used in other SoCs besides
> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
> these other SoCs may not resume at noirq time.
>
> But on a second thought, this PMIC seems to be designed specially for these two
> Exynos SoCs so I guess it's safe to assume that it is not needed?

Right, there's a close coupling between PMICs and SoCs.  The PMIC has
special sequencing and default voltage levels that were tuned exactly
for this SoC.

Note: Wolfram has not actually responded to my patch much less
accepted it.  It's entirely possible that in another month or two
we'll hear back a big fat NAK.  In that case your solution will be the
best one I can think of.


-Doug

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:29             ` Doug Anderson
  0 siblings, 0 replies; 76+ messages in thread
From: Doug Anderson @ 2014-06-26 16:29 UTC (permalink / raw)
  To: linux-arm-kernel

Javier,

On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
<javier.martinez@collabora.co.uk> wrote:
> Hello Doug,
>
> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>> Javier,
>>
>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>> <javier.martinez@collabora.co.uk> wrote:
>>>>> +
>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>> +static int max77802_suspend(struct device *dev)
>>>>> +{
>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>> +
>>>>> +    if (device_may_wakeup(dev))
>>>>> +            enable_irq_wake(max77802->irq);
>>>>> +
>>>>> +    disable_irq(max77802->irq);
>>>>
>>>> Can you add short comment why this is needed? I know why but just for
>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>> while suspending?" :). Especially that this is rather a workaround for
>>>> issue in other driver (I2C bus).
>>>>
>>>
>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>> figure out what what's going on here.
>>
>> Is the disable_irq() needed if you have
>> <https://patchwork.kernel.org/patch/4421891/>?
>>
>
> Probably not but I added the following comment:
>
>         /*
>          * The IRQ must be disabled during suspend since due wakeup
>          * ordering issues it may be possible that the I2C controller
>          * is still suspended when the interrupt happens so the IRQ
>          * handler will fail to read the I2C bus.
>          */
>         disable_irq(max77802->irq);
>
> since in theory this PMIC can be used in other SoCs besides
> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
> these other SoCs may not resume at noirq time.
>
> But on a second thought, this PMIC seems to be designed specially for these two
> Exynos SoCs so I guess it's safe to assume that it is not needed?

Right, there's a close coupling between PMICs and SoCs.  The PMIC has
special sequencing and default voltage levels that were tuned exactly
for this SoC.

Note: Wolfram has not actually responded to my patch much less
accepted it.  It's entirely possible that in another month or two
we'll hear back a big fat NAK.  In that case your solution will be the
best one I can think of.


-Doug

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
  2014-06-26 16:29             ` Doug Anderson
  (?)
@ 2014-06-26 16:36               ` Javier Martinez Canillas
  -1 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:36 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hello Doug,

On 06/26/2014 06:29 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>> Hello Doug,
>>
>> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>>> Javier,
>>>
>>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>>> <javier.martinez@collabora.co.uk> wrote:
>>>>>> +
>>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>>> +static int max77802_suspend(struct device *dev)
>>>>>> +{
>>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>>> +
>>>>>> +    if (device_may_wakeup(dev))
>>>>>> +            enable_irq_wake(max77802->irq);
>>>>>> +
>>>>>> +    disable_irq(max77802->irq);
>>>>>
>>>>> Can you add short comment why this is needed? I know why but just for
>>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>>> while suspending?" :). Especially that this is rather a workaround for
>>>>> issue in other driver (I2C bus).
>>>>>
>>>>
>>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>>> figure out what what's going on here.
>>>
>>> Is the disable_irq() needed if you have
>>> <https://patchwork.kernel.org/patch/4421891/>?
>>>
>>
>> Probably not but I added the following comment:
>>
>>         /*
>>          * The IRQ must be disabled during suspend since due wakeup
>>          * ordering issues it may be possible that the I2C controller
>>          * is still suspended when the interrupt happens so the IRQ
>>          * handler will fail to read the I2C bus.
>>          */
>>         disable_irq(max77802->irq);
>>
>> since in theory this PMIC can be used in other SoCs besides
>> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
>> these other SoCs may not resume at noirq time.
>>
>> But on a second thought, this PMIC seems to be designed specially for these two
>> Exynos SoCs so I guess it's safe to assume that it is not needed?
> 
> Right, there's a close coupling between PMICs and SoCs.  The PMIC has
> special sequencing and default voltage levels that were tuned exactly
> for this SoC.
> 
> Note: Wolfram has not actually responded to my patch much less
> accepted it.  It's entirely possible that in another month or two
> we'll hear back a big fat NAK.  In that case your solution will be the
> best one I can think of.
>

Ok, in that case I'll leave as is for now and add the comment but later once/if
your patch is merged, this can be removed.

> 
> -Doug
> 

Best regards,
Javier

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

* Re: [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:36               ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:36 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Krzysztof Kozlowski, Lee Jones, Samuel Ortiz, Mark Brown,
	Mike Turquette, Liam Girdwood, Alessandro Zummo, Kukjin Kim,
	Olof Johansson, Sjoerd Simons, Daniel Stone, Tomeu Vizoso,
	linux-arm-kernel, devicetree, linux-samsung-soc, linux-kernel

Hello Doug,

On 06/26/2014 06:29 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>> Hello Doug,
>>
>> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>>> Javier,
>>>
>>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>>> <javier.martinez@collabora.co.uk> wrote:
>>>>>> +
>>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>>> +static int max77802_suspend(struct device *dev)
>>>>>> +{
>>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>>> +
>>>>>> +    if (device_may_wakeup(dev))
>>>>>> +            enable_irq_wake(max77802->irq);
>>>>>> +
>>>>>> +    disable_irq(max77802->irq);
>>>>>
>>>>> Can you add short comment why this is needed? I know why but just for
>>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>>> while suspending?" :). Especially that this is rather a workaround for
>>>>> issue in other driver (I2C bus).
>>>>>
>>>>
>>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>>> figure out what what's going on here.
>>>
>>> Is the disable_irq() needed if you have
>>> <https://patchwork.kernel.org/patch/4421891/>?
>>>
>>
>> Probably not but I added the following comment:
>>
>>         /*
>>          * The IRQ must be disabled during suspend since due wakeup
>>          * ordering issues it may be possible that the I2C controller
>>          * is still suspended when the interrupt happens so the IRQ
>>          * handler will fail to read the I2C bus.
>>          */
>>         disable_irq(max77802->irq);
>>
>> since in theory this PMIC can be used in other SoCs besides
>> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
>> these other SoCs may not resume at noirq time.
>>
>> But on a second thought, this PMIC seems to be designed specially for these two
>> Exynos SoCs so I guess it's safe to assume that it is not needed?
> 
> Right, there's a close coupling between PMICs and SoCs.  The PMIC has
> special sequencing and default voltage levels that were tuned exactly
> for this SoC.
> 
> Note: Wolfram has not actually responded to my patch much less
> accepted it.  It's entirely possible that in another month or two
> we'll hear back a big fat NAK.  In that case your solution will be the
> best one I can think of.
>

Ok, in that case I'll leave as is for now and add the comment but later once/if
your patch is merged, this can be removed.

> 
> -Doug
> 

Best regards,
Javier

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

* [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC
@ 2014-06-26 16:36               ` Javier Martinez Canillas
  0 siblings, 0 replies; 76+ messages in thread
From: Javier Martinez Canillas @ 2014-06-26 16:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Doug,

On 06/26/2014 06:29 PM, Doug Anderson wrote:
> Javier,
> 
> On Thu, Jun 26, 2014 at 9:18 AM, Javier Martinez Canillas
> <javier.martinez@collabora.co.uk> wrote:
>> Hello Doug,
>>
>> On 06/26/2014 06:12 PM, Doug Anderson wrote:
>>> Javier,
>>>
>>> On Thu, Jun 26, 2014 at 4:13 AM, Javier Martinez Canillas
>>> <javier.martinez@collabora.co.uk> wrote:
>>>>>> +
>>>>>> +#ifdef CONFIG_PM_SLEEP
>>>>>> +static int max77802_suspend(struct device *dev)
>>>>>> +{
>>>>>> +    struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>>>>>> +    struct max77802_dev *max77802 = i2c_get_clientdata(i2c);
>>>>>> +
>>>>>> +    if (device_may_wakeup(dev))
>>>>>> +            enable_irq_wake(max77802->irq);
>>>>>> +
>>>>>> +    disable_irq(max77802->irq);
>>>>>
>>>>> Can you add short comment why this is needed? I know why but just for
>>>>> future generations which will wonder: "why do we need to disable the IRQ
>>>>> while suspending?" :). Especially that this is rather a workaround for
>>>>> issue in other driver (I2C bus).
>>>>>
>>>>
>>>> Good idea, I'll add a comment here on next version so code archaeologists can
>>>> figure out what what's going on here.
>>>
>>> Is the disable_irq() needed if you have
>>> <https://patchwork.kernel.org/patch/4421891/>?
>>>
>>
>> Probably not but I added the following comment:
>>
>>         /*
>>          * The IRQ must be disabled during suspend since due wakeup
>>          * ordering issues it may be possible that the I2C controller
>>          * is still suspended when the interrupt happens so the IRQ
>>          * handler will fail to read the I2C bus.
>>          */
>>         disable_irq(max77802->irq);
>>
>> since in theory this PMIC can be used in other SoCs besides
>> Exynos5420/Exynos5800 and it may be possible that the I2C controller driver for
>> these other SoCs may not resume at noirq time.
>>
>> But on a second thought, this PMIC seems to be designed specially for these two
>> Exynos SoCs so I guess it's safe to assume that it is not needed?
> 
> Right, there's a close coupling between PMICs and SoCs.  The PMIC has
> special sequencing and default voltage levels that were tuned exactly
> for this SoC.
> 
> Note: Wolfram has not actually responded to my patch much less
> accepted it.  It's entirely possible that in another month or two
> we'll hear back a big fat NAK.  In that case your solution will be the
> best one I can think of.
>

Ok, in that case I'll leave as is for now and add the comment but later once/if
your patch is merged, this can be removed.

> 
> -Doug
> 

Best regards,
Javier

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

end of thread, other threads:[~2014-06-26 16:36 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-25 19:03 [PATCH v4 00/14] Add Maxim 77802 PMIC support Javier Martinez Canillas
2014-06-25 19:03 ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 01/14] mfd: max77686: Convert to use regmap_irq Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 02/14] mfd: max77686: Allow the max77686 rtc to wakeup the system Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26  9:03   ` Krzysztof Kozlowski
2014-06-26  9:03     ` Krzysztof Kozlowski
2014-06-25 19:03 ` [PATCH v4 03/14] clk: max77686: Add DT include for MAX77686 PMIC clock Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 04/14] clk: max77686: Improve Maxim 77686 PMIC clocks binding Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:54   ` Doug Anderson
2014-06-25 19:54     ` Doug Anderson
2014-06-25 19:54     ` Doug Anderson
2014-06-25 19:03 ` [PATCH v4 05/14] clk: Add generic driver for Maxim PMIC clocks Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26  9:00   ` Krzysztof Kozlowski
2014-06-26  9:00     ` Krzysztof Kozlowski
2014-06-26 11:51   ` Yadwinder Singh Brar
2014-06-26 11:51     ` Yadwinder Singh Brar
2014-06-26 11:51     ` Yadwinder Singh Brar
2014-06-26 12:31     ` Javier Martinez Canillas
2014-06-26 12:31       ` Javier Martinez Canillas
2014-06-26 12:31       ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 06/14] clk: max77686: Convert to the generic max clock driver Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 07/14] mfd: Add driver for Maxim 77802 Power Management IC Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26  9:31   ` Krzysztof Kozlowski
2014-06-26  9:31     ` Krzysztof Kozlowski
2014-06-26 11:13     ` Javier Martinez Canillas
2014-06-26 11:13       ` Javier Martinez Canillas
2014-06-26 16:12       ` Doug Anderson
2014-06-26 16:12         ` Doug Anderson
2014-06-26 16:12         ` Doug Anderson
2014-06-26 16:18         ` Javier Martinez Canillas
2014-06-26 16:18           ` Javier Martinez Canillas
2014-06-26 16:18           ` Javier Martinez Canillas
2014-06-26 16:29           ` Doug Anderson
2014-06-26 16:29             ` Doug Anderson
2014-06-26 16:29             ` Doug Anderson
2014-06-26 16:36             ` Javier Martinez Canillas
2014-06-26 16:36               ` Javier Martinez Canillas
2014-06-26 16:36               ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 08/14] mfd: max77802: Add DT binding documentation Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 09/14] regmap: Add regmap_reg_copy function Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 10/14] regulator: Add driver for Maxim 77802 PMIC regulators Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26 10:08   ` Krzysztof Kozlowski
2014-06-26 10:08     ` Krzysztof Kozlowski
2014-06-26 11:26     ` Javier Martinez Canillas
2014-06-26 11:26       ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 11/14] clk: Add driver for Maxim 77802 PMIC clocks Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26 10:40   ` Krzysztof Kozlowski
2014-06-26 10:40     ` Krzysztof Kozlowski
2014-06-26 10:40     ` Krzysztof Kozlowski
2014-06-25 19:03 ` [PATCH v4 12/14] clk: max77802: Add DT binding documentation Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 13/14] rtc: Add driver for Maxim 77802 PMIC Real-Time-Clock Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-25 19:03 ` [PATCH v4 14/14] ARM: dts: Add max77802 to exynos5420-peach-pit and exynos5800-peach-pi Javier Martinez Canillas
2014-06-25 19:03   ` Javier Martinez Canillas
2014-06-26 13:32 ` [PATCH v4 00/14] Add Maxim 77802 PMIC support Naveen Krishna Ch
2014-06-26 13:32   ` Naveen Krishna Ch
2014-06-26 13:32   ` Naveen Krishna Ch
2014-06-26 13:56   ` Javier Martinez Canillas
2014-06-26 13:56     ` Javier Martinez Canillas
2014-06-26 13:56     ` Javier Martinez Canillas

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.